no-frills-ui 0.0.14-alpha.4 → 0.0.14-alpha.5

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 (132) hide show
  1. package/dist/index.js +1335 -493
  2. package/dist/index.js.map +1 -1
  3. package/lib-esm/components/Accordion/AccordionStep.d.ts.map +1 -1
  4. package/lib-esm/components/Accordion/AccordionStep.js +11 -29
  5. package/lib-esm/components/Accordion/AccordionStep.js.map +1 -1
  6. package/lib-esm/components/Badge/Badge.js +7 -7
  7. package/lib-esm/components/Badge/Badge.js.map +1 -1
  8. package/lib-esm/components/Button/ActionButton.d.ts.map +1 -1
  9. package/lib-esm/components/Button/ActionButton.js +12 -11
  10. package/lib-esm/components/Button/ActionButton.js.map +1 -1
  11. package/lib-esm/components/Button/Button.d.ts.map +1 -1
  12. package/lib-esm/components/Button/Button.js +14 -13
  13. package/lib-esm/components/Button/Button.js.map +1 -1
  14. package/lib-esm/components/Button/IconButton.d.ts.map +1 -1
  15. package/lib-esm/components/Button/IconButton.js +15 -14
  16. package/lib-esm/components/Button/IconButton.js.map +1 -1
  17. package/lib-esm/components/Button/LinkButton.d.ts.map +1 -1
  18. package/lib-esm/components/Button/LinkButton.js +7 -6
  19. package/lib-esm/components/Button/LinkButton.js.map +1 -1
  20. package/lib-esm/components/Button/RaisedButton.d.ts.map +1 -1
  21. package/lib-esm/components/Button/RaisedButton.js +15 -14
  22. package/lib-esm/components/Button/RaisedButton.js.map +1 -1
  23. package/lib-esm/components/Card/Card.d.ts.map +1 -1
  24. package/lib-esm/components/Card/Card.js +4 -4
  25. package/lib-esm/components/Card/Card.js.map +1 -1
  26. package/lib-esm/components/Chip/Chip.js +8 -8
  27. package/lib-esm/components/Chip/Chip.js.map +1 -1
  28. package/lib-esm/components/ChipInput/ChipInput.js +20 -20
  29. package/lib-esm/components/ChipInput/ChipInput.js.map +1 -1
  30. package/lib-esm/components/Dialog/AlertDialog.d.ts.map +1 -1
  31. package/lib-esm/components/Dialog/AlertDialog.js +4 -1
  32. package/lib-esm/components/Dialog/AlertDialog.js.map +1 -1
  33. package/lib-esm/components/Dialog/Dialog.d.ts +26 -1
  34. package/lib-esm/components/Dialog/Dialog.d.ts.map +1 -1
  35. package/lib-esm/components/Dialog/Dialog.js +84 -1
  36. package/lib-esm/components/Dialog/Dialog.js.map +1 -1
  37. package/lib-esm/components/DragAndDrop/DragItem.js +8 -8
  38. package/lib-esm/components/DragAndDrop/DragItem.js.map +1 -1
  39. package/lib-esm/components/Drawer/Drawer.d.ts +76 -1
  40. package/lib-esm/components/Drawer/Drawer.d.ts.map +1 -1
  41. package/lib-esm/components/Drawer/Drawer.js +158 -24
  42. package/lib-esm/components/Drawer/Drawer.js.map +1 -1
  43. package/lib-esm/components/Groups/Group.d.ts.map +1 -1
  44. package/lib-esm/components/Groups/Group.js +10 -8
  45. package/lib-esm/components/Groups/Group.js.map +1 -1
  46. package/lib-esm/components/Groups/GroupLabel.d.ts.map +1 -1
  47. package/lib-esm/components/Groups/GroupLabel.js +3 -3
  48. package/lib-esm/components/Groups/GroupLabel.js.map +1 -1
  49. package/lib-esm/components/Input/Checkbox.d.ts.map +1 -1
  50. package/lib-esm/components/Input/Checkbox.js +63 -58
  51. package/lib-esm/components/Input/Checkbox.js.map +1 -1
  52. package/lib-esm/components/Input/Dropdown.d.ts +8 -0
  53. package/lib-esm/components/Input/Dropdown.d.ts.map +1 -1
  54. package/lib-esm/components/Input/Dropdown.js +54 -31
  55. package/lib-esm/components/Input/Dropdown.js.map +1 -1
  56. package/lib-esm/components/Input/Input.d.ts.map +1 -1
  57. package/lib-esm/components/Input/Input.js +27 -21
  58. package/lib-esm/components/Input/Input.js.map +1 -1
  59. package/lib-esm/components/Input/Radio.d.ts.map +1 -1
  60. package/lib-esm/components/Input/Radio.js +58 -42
  61. package/lib-esm/components/Input/Radio.js.map +1 -1
  62. package/lib-esm/components/Input/RadioButton.d.ts.map +1 -1
  63. package/lib-esm/components/Input/RadioButton.js +12 -12
  64. package/lib-esm/components/Input/RadioButton.js.map +1 -1
  65. package/lib-esm/components/Input/Select.d.ts.map +1 -1
  66. package/lib-esm/components/Input/Select.js +27 -21
  67. package/lib-esm/components/Input/Select.js.map +1 -1
  68. package/lib-esm/components/Input/TextArea.d.ts.map +1 -1
  69. package/lib-esm/components/Input/TextArea.js +27 -21
  70. package/lib-esm/components/Input/TextArea.js.map +1 -1
  71. package/lib-esm/components/Input/Toggle.d.ts.map +1 -1
  72. package/lib-esm/components/Input/Toggle.js +17 -14
  73. package/lib-esm/components/Input/Toggle.js.map +1 -1
  74. package/lib-esm/components/Menu/Menu.d.ts +13 -1
  75. package/lib-esm/components/Menu/Menu.d.ts.map +1 -1
  76. package/lib-esm/components/Menu/Menu.js +98 -3
  77. package/lib-esm/components/Menu/Menu.js.map +1 -1
  78. package/lib-esm/components/Menu/MenuItem.d.ts +6 -3
  79. package/lib-esm/components/Menu/MenuItem.d.ts.map +1 -1
  80. package/lib-esm/components/Menu/MenuItem.js +10 -10
  81. package/lib-esm/components/Menu/MenuItem.js.map +1 -1
  82. package/lib-esm/components/Modal/Modal.d.ts +70 -1
  83. package/lib-esm/components/Modal/Modal.d.ts.map +1 -1
  84. package/lib-esm/components/Modal/Modal.js +145 -11
  85. package/lib-esm/components/Modal/Modal.js.map +1 -1
  86. package/lib-esm/components/Notification/Notification.d.ts +3 -1
  87. package/lib-esm/components/Notification/Notification.d.ts.map +1 -1
  88. package/lib-esm/components/Notification/Notification.js +4 -2
  89. package/lib-esm/components/Notification/Notification.js.map +1 -1
  90. package/lib-esm/components/Notification/NotificationManager.d.ts +11 -1
  91. package/lib-esm/components/Notification/NotificationManager.d.ts.map +1 -1
  92. package/lib-esm/components/Notification/NotificationManager.js +43 -8
  93. package/lib-esm/components/Notification/NotificationManager.js.map +1 -1
  94. package/lib-esm/components/Notification/style.d.ts +4 -0
  95. package/lib-esm/components/Notification/style.d.ts.map +1 -1
  96. package/lib-esm/components/Notification/style.js +30 -15
  97. package/lib-esm/components/Notification/style.js.map +1 -1
  98. package/lib-esm/components/Notification/types.d.ts +2 -0
  99. package/lib-esm/components/Notification/types.d.ts.map +1 -1
  100. package/lib-esm/components/Notification/types.js.map +1 -1
  101. package/lib-esm/components/Popover/Popover.d.ts.map +1 -1
  102. package/lib-esm/components/Popover/Popover.js +17 -2
  103. package/lib-esm/components/Popover/Popover.js.map +1 -1
  104. package/lib-esm/components/Spinner/Spinner.d.ts +3 -0
  105. package/lib-esm/components/Spinner/Spinner.d.ts.map +1 -1
  106. package/lib-esm/components/Spinner/Spinner.js +19 -4
  107. package/lib-esm/components/Spinner/Spinner.js.map +1 -1
  108. package/lib-esm/components/Stepper/Stepper.d.ts.map +1 -1
  109. package/lib-esm/components/Stepper/Stepper.js +29 -10
  110. package/lib-esm/components/Stepper/Stepper.js.map +1 -1
  111. package/lib-esm/components/Tabs/Tabs.d.ts.map +1 -1
  112. package/lib-esm/components/Tabs/Tabs.js +45 -12
  113. package/lib-esm/components/Tabs/Tabs.js.map +1 -1
  114. package/lib-esm/components/Toast/Toast.d.ts +25 -4
  115. package/lib-esm/components/Toast/Toast.d.ts.map +1 -1
  116. package/lib-esm/components/Toast/Toast.js +114 -18
  117. package/lib-esm/components/Toast/Toast.js.map +1 -1
  118. package/lib-esm/components/Tooltip/Tooltip.d.ts.map +1 -1
  119. package/lib-esm/components/Tooltip/Tooltip.js +16 -5
  120. package/lib-esm/components/Tooltip/Tooltip.js.map +1 -1
  121. package/lib-esm/shared/LayerManager.d.ts.map +1 -1
  122. package/lib-esm/shared/LayerManager.js +63 -1
  123. package/lib-esm/shared/LayerManager.js.map +1 -1
  124. package/lib-esm/shared/constants.d.ts +58 -27
  125. package/lib-esm/shared/constants.d.ts.map +1 -1
  126. package/lib-esm/shared/constants.js +88 -25
  127. package/lib-esm/shared/constants.js.map +1 -1
  128. package/lib-esm/shared/styles.d.ts +1 -1
  129. package/lib-esm/shared/styles.d.ts.map +1 -1
  130. package/lib-esm/shared/styles.js +5 -3
  131. package/lib-esm/shared/styles.js.map +1 -1
  132. package/package.json +1 -1
@@ -15,14 +15,41 @@ import PropTypes from 'prop-types';
15
15
  import LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';
16
16
  export { Header as ModalHeader, Body as ModalBody, Footer as ModalFooter, } from '../../shared/styles';
17
17
  import { DialogContainer as ModalContainer } from '../Dialog/Dialog';
18
+ const modalPropTypes = {
19
+ /** Opens the modal */
20
+ open: PropTypes.bool.isRequired,
21
+ /** Closes the modal on esc */
22
+ closeOnEsc: PropTypes.bool,
23
+ /** Closes the modal on overlay click */
24
+ closeOnOverlayClick: PropTypes.bool,
25
+ /** Call back function called when the modal closes. */
26
+ onClose: PropTypes.func,
27
+ };
28
+ /**
29
+ * Modal component
30
+ *
31
+ * A dialog window that sits on top of the main application content.
32
+ * It disrupts the user's workflow to demand attention for a critical task or decision.
33
+ *
34
+ * Accessibility:
35
+ * - Implements ARIA `role="dialog"` and `aria-modal="true"`.
36
+ * - Traps focus effectively within the modal while open.
37
+ * - Restores focus to the triggering element upon closure.
38
+ * - Supports closing via ESC key and overlay click.
39
+ */
18
40
  class Modal extends React.Component {
19
41
  constructor() {
20
42
  super(...arguments);
21
43
  this.state = {
22
44
  open: false,
23
45
  };
46
+ /**
47
+ * Internal close handler.
48
+ * Restores focus and calls the external onClose callback.
49
+ */
24
50
  this.onClose = () => {
25
51
  var _a, _b;
52
+ this.restoreFocus();
26
53
  this.setState({
27
54
  open: false,
28
55
  });
@@ -30,7 +57,97 @@ class Modal extends React.Component {
30
57
  this.closeCallback = null;
31
58
  this.layer = null;
32
59
  };
60
+ this.lastFocusedElement = null;
61
+ this.modalRef = React.createRef();
62
+ /**
63
+ * Retrieves all focusable elements within the modal.
64
+ */
65
+ this.getFocusableElements = () => {
66
+ if (!this.modalRef.current)
67
+ return [];
68
+ return Array.from(this.modalRef.current.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'));
69
+ };
70
+ /**
71
+ * Handles keydown events to implement the focus trap.
72
+ * Traps Tab and Shift+Tab within the modal.
73
+ */
74
+ this.handleKeyDown = (e) => {
75
+ if (e.key === 'Tab') {
76
+ const focusableElements = this.getFocusableElements();
77
+ if (focusableElements.length === 0)
78
+ return;
79
+ const firstElement = focusableElements[0];
80
+ const lastElement = focusableElements[focusableElements.length - 1];
81
+ if (e.shiftKey) {
82
+ if (document.activeElement === firstElement) {
83
+ lastElement.focus();
84
+ e.preventDefault();
85
+ }
86
+ }
87
+ else {
88
+ if (document.activeElement === lastElement) {
89
+ firstElement.focus();
90
+ e.preventDefault();
91
+ }
92
+ }
93
+ }
94
+ };
95
+ /**
96
+ * Restores focus to the element that was focused before the modal opened.
97
+ */
98
+ this.restoreFocus = () => {
99
+ if (this.lastFocusedElement) {
100
+ // Check if the element is still in the document
101
+ const elementToBeFocused = this.lastFocusedElement;
102
+ this.lastFocusedElement = null;
103
+ setTimeout(() => {
104
+ if (document.body.contains(elementToBeFocused)) {
105
+ elementToBeFocused.focus();
106
+ }
107
+ }, 100);
108
+ }
109
+ };
110
+ /**
111
+ * Callback ref to capture the Modal DOM element.
112
+ * Triggers initial focus setting when the element mounts.
113
+ */
114
+ this.setModalRef = (node) => {
115
+ // Update ref
116
+ this.modalRef.current = node;
117
+ if (node) {
118
+ // Set initial focus when the node is mounted
119
+ this.setInitialFocus(node);
120
+ }
121
+ };
122
+ /**
123
+ * Sets initial focus within the modal.
124
+ * Tries to focus the header (first child) first, then the first interactive element, or falls back to the container.
125
+ */
126
+ this.setInitialFocus = (root) => {
127
+ // Try to find the header (assumed to be the first child)
128
+ const firstChild = root.firstElementChild;
129
+ if (firstChild) {
130
+ // Ensure it's focusable
131
+ if (firstChild.getAttribute('tabindex') === null) {
132
+ firstChild.setAttribute('tabindex', '-1');
133
+ }
134
+ firstChild.focus();
135
+ return;
136
+ }
137
+ // Fallback to focusable elements
138
+ const focusableElements = this.getFocusableElements();
139
+ if (focusableElements.length > 0) {
140
+ focusableElements[0].focus();
141
+ }
142
+ else {
143
+ // Fallback to container
144
+ root.focus();
145
+ }
146
+ };
33
147
  }
148
+ /**
149
+ * Syncs state with props.
150
+ */
34
151
  static getDerivedStateFromProps(props) {
35
152
  if (props.open) {
36
153
  return {
@@ -39,13 +156,36 @@ class Modal extends React.Component {
39
156
  }
40
157
  return null;
41
158
  }
159
+ /**
160
+ * Lifecycle method to save the currently focused element when the modal mounts while open.
161
+ */
162
+ componentDidMount() {
163
+ if (this.props.open) {
164
+ this.lastFocusedElement = document.activeElement;
165
+ }
166
+ }
167
+ /**
168
+ * Lifecycle method to restore focus when the modal unmounts.
169
+ */
170
+ componentWillUnmount() {
171
+ if (this.props.open) {
172
+ this.restoreFocus();
173
+ }
174
+ }
175
+ /**
176
+ * Lifecycle method to handle Modal updates.
177
+ * Manages opening/closing logic via LayerManager and focus preservation.
178
+ */
42
179
  getSnapshotBeforeUpdate(prevProps) {
43
180
  var _a;
44
181
  const _b = this.props, { open, closeOnEsc, closeOnOverlayClick, children } = _b, rest = __rest(_b, ["open", "closeOnEsc", "closeOnOverlayClick", "children"]);
45
182
  if (prevProps.open && !open) {
46
183
  (_a = this.closeCallback) === null || _a === void 0 ? void 0 : _a.call(this);
184
+ this.restoreFocus();
47
185
  }
48
186
  if (!prevProps.open && open) {
187
+ // Save current focus
188
+ this.lastFocusedElement = document.activeElement;
49
189
  this.layer = LayerManager.renderLayer({
50
190
  overlay: true,
51
191
  exitDelay: 300,
@@ -53,12 +193,15 @@ class Modal extends React.Component {
53
193
  closeCallback: this.onClose,
54
194
  closeOnEsc: closeOnEsc,
55
195
  closeOnOverlayClick: closeOnOverlayClick,
56
- component: (_jsx(ModalContainer, Object.assign({}, rest, { onClick: (e) => e.stopPropagation(), elevated: true, children: children }))),
196
+ component: (_jsx(ModalContainer, Object.assign({}, rest, { ref: this.setModalRef, role: "dialog", "aria-modal": "true", tabIndex: -1, onKeyDown: this.handleKeyDown, onClick: (e) => e.stopPropagation(), elevated: true, children: children }))),
57
197
  });
58
198
  this.closeCallback = this.layer[1];
59
199
  this.forceUpdate();
60
200
  }
61
201
  }
202
+ /**
203
+ * Renders the Modal component via the LayerManager portal.
204
+ */
62
205
  render() {
63
206
  if (this.state.open && this.layer) {
64
207
  const [Component] = this.layer;
@@ -67,16 +210,7 @@ class Modal extends React.Component {
67
210
  return null;
68
211
  }
69
212
  }
70
- Modal.propTypes = {
71
- /** Opens the modal */
72
- open: PropTypes.bool.isRequired,
73
- /** Closes the modal on esc */
74
- closeOnEsc: PropTypes.bool,
75
- /** Closes the modal on overlay click */
76
- closeOnOverlayClick: PropTypes.bool,
77
- /** Call back function called when the modal closes. */
78
- onClose: PropTypes.func,
79
- };
213
+ Modal.propTypes = modalPropTypes;
80
214
  Modal.defaultProps = {
81
215
  closeOnEsc: true,
82
216
  closeOnOverlayClick: true,
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../../src/components/Modal/Modal.tsx"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,YAAY,EAAE,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EACH,MAAM,IAAI,WAAW,EACrB,IAAI,IAAI,SAAS,EACjB,MAAM,IAAI,WAAW,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAQrE,MAAqB,KAAM,SAAQ,KAAK,CAAC,SAGxC;IAHD;;QAII,UAAK,GAAG;YACJ,IAAI,EAAE,KAAK;SACd,CAAC;QA+BM,YAAO,GAAG,GAAG,EAAE;;YACnB,IAAI,CAAC,QAAQ,CAAC;gBACV,IAAI,EAAE,KAAK;aACd,CAAC,CAAC;YACH,MAAA,MAAA,IAAI,CAAC,KAAK,EAAC,OAAO,kDAAI,CAAC;YACvB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACtB,CAAC,CAAC;IAoCN,CAAC;IAxDG,MAAM,CAAC,wBAAwB,CAAC,KAAiB;QAC7C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACb,OAAO;gBACH,IAAI,EAAE,IAAI;aACb,CAAC;QACN,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAeD,uBAAuB,CAAC,SAAqB;;QACzC,MAAM,KAA+D,IAAI,CAAC,KAAK,EAAzE,EAAE,IAAI,EAAE,UAAU,EAAE,mBAAmB,EAAE,QAAQ,OAAwB,EAAnB,IAAI,cAA1D,yDAA4D,CAAa,CAAC;QAEhF,IAAI,SAAS,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAA,IAAI,CAAC,aAAa,oDAAI,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC;gBAClC,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,GAAG;gBACd,QAAQ,EAAE,cAAc,CAAC,MAAM;gBAC/B,aAAa,EAAE,IAAI,CAAC,OAAO;gBAC3B,UAAU,EAAE,UAAU;gBACtB,mBAAmB,EAAE,mBAAmB;gBACxC,SAAS,EAAE,CACP,KAAC,cAAc,oBAAK,IAAI,IAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EAAE,QAAQ,kBAClE,QAAQ,IACI,CACpB;aACJ,CAAC,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnC,IAAI,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;IACL,CAAC;IAED,MAAM;QACF,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YAC/B,OAAO,KAAC,SAAS,KAAG,CAAC;QACzB,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;;AAvEM,eAAS,GAAG;IACf,sBAAsB;IACtB,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,UAAU;IAC/B,8BAA8B;IAC9B,UAAU,EAAE,SAAS,CAAC,IAAI;IAC1B,wCAAwC;IACxC,mBAAmB,EAAE,SAAS,CAAC,IAAI;IACnC,uDAAuD;IACvD,OAAO,EAAE,SAAS,CAAC,IAAI;CAC1B,AATe,CASd;AAEK,kBAAY,GAAG;IAClB,UAAU,EAAE,IAAI;IAChB,mBAAmB,EAAE,IAAI;CAC5B,AAHkB,CAGjB;eAtBe,KAAK","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nexport {\n Header as ModalHeader,\n Body as ModalBody,\n Footer as ModalFooter,\n} from '../../shared/styles';\nimport { DialogContainer as ModalContainer } from '../Dialog/Dialog';\n\ntype ModalProps = PropTypes.InferProps<typeof Modal.propTypes>;\n\ninterface ModalState {\n open: boolean;\n}\n\nexport default class Modal extends React.Component<\n React.PropsWithChildren<ModalProps>,\n ModalState\n> {\n state = {\n open: false,\n };\n\n static propTypes = {\n /** Opens the modal */\n open: PropTypes.bool.isRequired,\n /** Closes the modal on esc */\n closeOnEsc: PropTypes.bool,\n /** Closes the modal on overlay click */\n closeOnOverlayClick: PropTypes.bool,\n /** Call back function called when the modal closes. */\n onClose: PropTypes.func,\n };\n\n static defaultProps = {\n closeOnEsc: true,\n closeOnOverlayClick: true,\n };\n\n static getDerivedStateFromProps(props: ModalProps) {\n if (props.open) {\n return {\n open: true,\n };\n }\n return null;\n }\n\n private layer: ReturnType<typeof LayerManager.renderLayer>;\n\n private closeCallback: (resp?: unknown) => void;\n\n private onClose = () => {\n this.setState({\n open: false,\n });\n this.props.onClose?.();\n this.closeCallback = null;\n this.layer = null;\n };\n\n getSnapshotBeforeUpdate(prevProps: ModalProps) {\n const { open, closeOnEsc, closeOnOverlayClick, children, ...rest } = this.props;\n\n if (prevProps.open && !open) {\n this.closeCallback?.();\n }\n\n if (!prevProps.open && open) {\n this.layer = LayerManager.renderLayer({\n overlay: true,\n exitDelay: 300,\n position: LAYER_POSITION.DIALOG,\n closeCallback: this.onClose,\n closeOnEsc: closeOnEsc,\n closeOnOverlayClick: closeOnOverlayClick,\n component: (\n <ModalContainer {...rest} onClick={(e) => e.stopPropagation()} elevated>\n {children}\n </ModalContainer>\n ),\n });\n this.closeCallback = this.layer[1];\n this.forceUpdate();\n }\n }\n\n render() {\n if (this.state.open && this.layer) {\n const [Component] = this.layer;\n return <Component />;\n }\n\n return null;\n }\n}\n"]}
1
+ {"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../../src/components/Modal/Modal.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport LayerManager, { LAYER_POSITION } from '../../shared/LayerManager';\nexport {\n Header as ModalHeader,\n Body as ModalBody,\n Footer as ModalFooter,\n} from '../../shared/styles';\nimport { DialogContainer as ModalContainer } from '../Dialog/Dialog';\n\nconst modalPropTypes = {\n /** Opens the modal */\n open: PropTypes.bool.isRequired,\n /** Closes the modal on esc */\n closeOnEsc: PropTypes.bool,\n /** Closes the modal on overlay click */\n closeOnOverlayClick: PropTypes.bool,\n /** Call back function called when the modal closes. */\n onClose: PropTypes.func,\n};\n\ntype ModalProps = PropTypes.InferProps<typeof modalPropTypes>;\n\ninterface ModalState {\n open: boolean;\n}\n\n/**\n * Modal component\n *\n * A dialog window that sits on top of the main application content.\n * It disrupts the user's workflow to demand attention for a critical task or decision.\n *\n * Accessibility:\n * - Implements ARIA `role=\"dialog\"` and `aria-modal=\"true\"`.\n * - Traps focus effectively within the modal while open.\n * - Restores focus to the triggering element upon closure.\n * - Supports closing via ESC key and overlay click.\n */\nexport default class Modal extends React.Component<\n React.PropsWithChildren<ModalProps>,\n ModalState\n> {\n state = {\n open: false,\n };\n\n static propTypes = modalPropTypes;\n\n static defaultProps = {\n closeOnEsc: true,\n closeOnOverlayClick: true,\n };\n\n /**\n * Syncs state with props.\n */\n static getDerivedStateFromProps(props: ModalProps) {\n if (props.open) {\n return {\n open: true,\n };\n }\n return null;\n }\n\n private layer: ReturnType<typeof LayerManager.renderLayer>;\n\n private closeCallback: (resp?: unknown) => void;\n\n /**\n * Internal close handler.\n * Restores focus and calls the external onClose callback.\n */\n private onClose = () => {\n this.restoreFocus();\n this.setState({\n open: false,\n });\n this.props.onClose?.();\n this.closeCallback = null;\n this.layer = null;\n };\n\n private lastFocusedElement: HTMLElement | null = null;\n private modalRef = React.createRef<HTMLDivElement>();\n\n /**\n * Retrieves all focusable elements within the modal.\n */\n private getFocusableElements = (): HTMLElement[] => {\n if (!this.modalRef.current) return [];\n return Array.from(\n this.modalRef.current.querySelectorAll(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n ),\n ) as HTMLElement[];\n };\n\n /**\n * Handles keydown events to implement the focus trap.\n * Traps Tab and Shift+Tab within the modal.\n */\n private handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Tab') {\n const focusableElements = this.getFocusableElements();\n if (focusableElements.length === 0) return;\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n lastElement.focus();\n e.preventDefault();\n }\n } else {\n if (document.activeElement === lastElement) {\n firstElement.focus();\n e.preventDefault();\n }\n }\n }\n };\n\n /**\n * Lifecycle method to save the currently focused element when the modal mounts while open.\n */\n componentDidMount() {\n if (this.props.open) {\n this.lastFocusedElement = document.activeElement as HTMLElement;\n }\n }\n\n /**\n * Lifecycle method to restore focus when the modal unmounts.\n */\n componentWillUnmount() {\n if (this.props.open) {\n this.restoreFocus();\n }\n }\n\n /**\n * Restores focus to the element that was focused before the modal opened.\n */\n private restoreFocus = () => {\n if (this.lastFocusedElement) {\n // Check if the element is still in the document\n const elementToBeFocused = this.lastFocusedElement;\n this.lastFocusedElement = null;\n setTimeout(() => {\n if (document.body.contains(elementToBeFocused)) {\n elementToBeFocused.focus();\n }\n }, 100);\n }\n };\n\n /**\n * Callback ref to capture the Modal DOM element.\n * Triggers initial focus setting when the element mounts.\n */\n private setModalRef = (node: HTMLDivElement | null) => {\n // Update ref\n (this.modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n\n if (node) {\n // Set initial focus when the node is mounted\n this.setInitialFocus(node);\n }\n };\n\n /**\n * Sets initial focus within the modal.\n * Tries to focus the header (first child) first, then the first interactive element, or falls back to the container.\n */\n private setInitialFocus = (root: HTMLElement) => {\n // Try to find the header (assumed to be the first child)\n const firstChild = root.firstElementChild as HTMLElement;\n if (firstChild) {\n // Ensure it's focusable\n if (firstChild.getAttribute('tabindex') === null) {\n firstChild.setAttribute('tabindex', '-1');\n }\n firstChild.focus();\n return;\n }\n\n // Fallback to focusable elements\n const focusableElements = this.getFocusableElements();\n if (focusableElements.length > 0) {\n focusableElements[0].focus();\n } else {\n // Fallback to container\n root.focus();\n }\n };\n\n /**\n * Lifecycle method to handle Modal updates.\n * Manages opening/closing logic via LayerManager and focus preservation.\n */\n getSnapshotBeforeUpdate(prevProps: ModalProps) {\n const { open, closeOnEsc, closeOnOverlayClick, children, ...rest } = this.props;\n\n if (prevProps.open && !open) {\n this.closeCallback?.();\n this.restoreFocus();\n }\n\n if (!prevProps.open && open) {\n // Save current focus\n this.lastFocusedElement = document.activeElement as HTMLElement;\n\n this.layer = LayerManager.renderLayer({\n overlay: true,\n exitDelay: 300,\n position: LAYER_POSITION.DIALOG,\n closeCallback: this.onClose,\n closeOnEsc: closeOnEsc,\n closeOnOverlayClick: closeOnOverlayClick,\n component: (\n <ModalContainer\n {...rest}\n ref={this.setModalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n tabIndex={-1}\n onKeyDown={this.handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n elevated\n >\n {children}\n </ModalContainer>\n ),\n });\n this.closeCallback = this.layer[1];\n this.forceUpdate();\n }\n }\n\n /**\n * Renders the Modal component via the LayerManager portal.\n */\n render() {\n if (this.state.open && this.layer) {\n const [Component] = this.layer;\n return <Component />;\n }\n\n return null;\n }\n}\n"]}
@@ -23,6 +23,8 @@ export declare class StoryProps extends React.Component<NotificationProps> {
23
23
  buttonClick: PropTypes.Requireable<(...args: any[]) => any>;
24
24
  /** Notification close callback. */
25
25
  onClose: PropTypes.Requireable<(...args: any[]) => any>;
26
+ /** Aria label for the close button on the notification. Defaults to "Close notification" */
27
+ closeButtonAriaLabel: PropTypes.Requireable<string>;
26
28
  };
27
29
  static defaultProps: {
28
30
  duration: number;
@@ -42,7 +44,7 @@ declare class Notification {
42
44
  * @param options - Configuration options for the notification
43
45
  * @returns The notification ID or a promise that resolves to the notification ID
44
46
  */
45
- add: (position: NOTIFICATION_POSITION, options: NotificationOptions) => string | Promise<unknown>;
47
+ add: (position: NOTIFICATION_POSITION, options: NotificationOptions, ariaLabel?: string) => Promise<string>;
46
48
  /**
47
49
  * Removes a notification
48
50
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.d.ts","sourceRoot":"","sources":["../../../src/components/Notification/Notification.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAChD,OAAO,SAAS,MAAM,YAAY,CAAC;AAKnC,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAExF,KAAK,iBAAiB,GAAG,SAAS,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;AAE3E,8DAA8D;AAC9D,qBAAa,UAAW,SAAQ,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC;IAC9D,MAAM,CAAC,SAAS;QACZ,gCAAgC;;QAEhC,+BAA+B;;QAE/B,wDAAwD;;QAExD,oDAAoD;;QAEpD,kCAAkC;;QAElC,2BAA2B;;QAO3B,yBAAyB;;QAEzB,mCAAmC;;QAEnC,mCAAmC;;MAErC;IAEF,MAAM,CAAC,YAAY;;;;MAIjB;IAEF,MAAM,IAAI,KAAK,CAAC,SAAS;CAG5B;AAUD,yBAAyB;AACzB,cAAM,YAAY;IACd,oEAAoE;IACpE,OAAO,CAAC,UAAU,CAOJ;IAEd;;;;;;OAMG;IACI,GAAG,aAAc,qBAAqB,WAAW,mBAAmB,+BAyDzE;IAEF;;;;;OAKG;IACI,MAAM,aAAc,qBAAqB,MAAM,MAAM,UAK1D;IAEF;;;;;OAKG;IACI,OAAO,aAAc,qBAAqB,UAS/C;CACL;AAED,kCAAkC;;AAClC,wBAAkC"}
1
+ {"version":3,"file":"Notification.d.ts","sourceRoot":"","sources":["../../../src/components/Notification/Notification.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAChD,OAAO,SAAS,MAAM,YAAY,CAAC;AAKnC,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAExF,KAAK,iBAAiB,GAAG,SAAS,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;AAE3E,8DAA8D;AAC9D,qBAAa,UAAW,SAAQ,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC;IAC9D,MAAM,CAAC,SAAS;QACZ,gCAAgC;;QAEhC,+BAA+B;;QAE/B,wDAAwD;;QAExD,oDAAoD;;QAEpD,kCAAkC;;QAElC,2BAA2B;;QAO3B,yBAAyB;;QAEzB,mCAAmC;;QAEnC,mCAAmC;;QAEnC,4FAA4F;;MAE9F;IAEF,MAAM,CAAC,YAAY;;;;MAIjB;IAEF,MAAM,IAAI,KAAK,CAAC,SAAS;CAG5B;AAUD,yBAAyB;AACzB,cAAM,YAAY;IACd,oEAAoE;IACpE,OAAO,CAAC,UAAU,CAOJ;IAEd;;;;;;OAMG;IACI,GAAG,aACI,qBAAqB,WACtB,mBAAmB,cACjB,MAAM,qBA2DnB;IAEF;;;;;OAKG;IACI,MAAM,aAAc,qBAAqB,MAAM,MAAM,UAK1D;IAEF;;;;;OAKG;IACI,OAAO,aAAc,qBAAqB,UAS/C;CACL;AAED,kCAAkC;;AAClC,wBAAkC"}
@@ -36,6 +36,8 @@ StoryProps.propTypes = {
36
36
  buttonClick: PropTypes.func,
37
37
  /** Notification close callback. */
38
38
  onClose: PropTypes.func,
39
+ /** Aria label for the close button on the notification. Defaults to "Close notification" */
40
+ closeButtonAriaLabel: PropTypes.string,
39
41
  };
40
42
  StoryProps.defaultProps = {
41
43
  duration: 5000,
@@ -61,7 +63,7 @@ class Notification {
61
63
  * @param options - Configuration options for the notification
62
64
  * @returns The notification ID or a promise that resolves to the notification ID
63
65
  */
64
- this.add = (position, options) => {
66
+ this.add = (position, options, ariaLabel = 'Notifications') => {
65
67
  if (!this.containers.has(position)) {
66
68
  /** Callback ref to capture the NotificationManager instance when it mounts */
67
69
  const refCallback = (instance) => {
@@ -77,7 +79,7 @@ class Notification {
77
79
  closeOnOverlayClick: false,
78
80
  position: positionMap[position],
79
81
  alwaysOnTop: true,
80
- component: (_jsx(NotificationManager, { ref: refCallback, position: position, onEmpty: () => this.destroy(position) })),
82
+ component: (_jsx(NotificationManager, { ref: refCallback, position: position, onEmpty: () => this.destroy(position), ariaLabel: ariaLabel })),
81
83
  });
82
84
  // Create a div to mount the Component
83
85
  const div = document.createElement('div');
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.js","sourceRoot":"","sources":["../../../src/components/Notification/Notification.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type RefCallback } from 'react';\nimport PropTypes from 'prop-types';\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 = PropTypes.InferProps<typeof StoryProps.propTypes>;\n\n/** This component is only used for storybook documentation */\nexport class StoryProps extends React.Component<NotificationProps> {\n static propTypes = {\n /** Title of the notification */\n title: PropTypes.string.isRequired,\n /** Body of the notification */\n description: PropTypes.string.isRequired,\n /** Id for the notification, helps in de-duplication. */\n id: PropTypes.string,\n /** Duration for the notification in milliseconds */\n duration: PropTypes.number,\n /** Creates sticky notification */\n sticky: PropTypes.bool,\n /** Type of notification */\n type: PropTypes.oneOf([\n NOTIFICATION_TYPE.INFO,\n NOTIFICATION_TYPE.SUCCESS,\n NOTIFICATION_TYPE.WARNING,\n NOTIFICATION_TYPE.DANGER,\n ]),\n /** Action button text */\n buttonText: PropTypes.string,\n /** Action button click callback */\n buttonClick: PropTypes.func,\n /** Notification close callback. */\n onClose: PropTypes.func,\n };\n\n static defaultProps = {\n duration: 5000,\n sticky: false,\n type: NOTIFICATION_TYPE.INFO,\n };\n\n render(): React.ReactNode {\n return null;\n }\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 = (position: NOTIFICATION_POSITION, options: NotificationOptions) => {\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 />\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((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"]}
1
+ {"version":3,"file":"Notification.js","sourceRoot":"","sources":["../../../src/components/Notification/Notification.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type RefCallback } from 'react';\nimport PropTypes from 'prop-types';\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 = PropTypes.InferProps<typeof StoryProps.propTypes>;\n\n/** This component is only used for storybook documentation */\nexport class StoryProps extends React.Component<NotificationProps> {\n static propTypes = {\n /** Title of the notification */\n title: PropTypes.string.isRequired,\n /** Body of the notification */\n description: PropTypes.string.isRequired,\n /** Id for the notification, helps in de-duplication. */\n id: PropTypes.string,\n /** Duration for the notification in milliseconds */\n duration: PropTypes.number,\n /** Creates sticky notification */\n sticky: PropTypes.bool,\n /** Type of notification */\n type: PropTypes.oneOf([\n NOTIFICATION_TYPE.INFO,\n NOTIFICATION_TYPE.SUCCESS,\n NOTIFICATION_TYPE.WARNING,\n NOTIFICATION_TYPE.DANGER,\n ]),\n /** Action button text */\n buttonText: PropTypes.string,\n /** Action button click callback */\n buttonClick: PropTypes.func,\n /** Notification close callback. */\n onClose: PropTypes.func,\n /** Aria label for the close button on the notification. Defaults to \"Close notification\" */\n closeButtonAriaLabel: PropTypes.string,\n };\n\n static defaultProps = {\n duration: 5000,\n sticky: false,\n type: NOTIFICATION_TYPE.INFO,\n };\n\n render(): React.ReactNode {\n return null;\n }\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"]}
@@ -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,6 +18,8 @@ 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
  *
@@ -28,7 +31,14 @@ declare class NotificationManager extends React.Component<NotificationManagerPro
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
  *
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationManager.d.ts","sourceRoot":"","sources":["../../../src/components/Notification/NotificationManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,EAAE,qBAAqB,EAAqB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAExF,UAAU,wBAAwB;IAE9B,QAAQ,EAAE,qBAAqB,CAAC;IAEhC,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAGD,UAAU,UAAW,SAAQ,mBAAmB;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAGD,UAAU,wBAAwB;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;CACzB;AAQD;;GAEG;AACH,cAAM,mBAAoB,SAAQ,KAAK,CAAC,SAAS,CAC7C,wBAAwB,EACxB,wBAAwB,CAC3B;IACG,KAAK,EAAE,wBAAwB,CAE7B;IAGF,OAAO,CAAC,QAAQ,CAAgB;IAGhC,OAAO,CAAC,GAAG,CAAqB;IAEhC;;;;OAIG;IACI,MAAM,OAAQ,MAAM,UAsCzB;IAEF;;;;OAIG;IACI,GAAG,WAAY,mBAAmB,YA8BvC;IAEF;;;;OAIG;IACI,iBAAiB,OAAQ,MAAM,gBAEpC;IAEF;;;;OAIG;IACI,KAAK,OAAQ,MAAM,gBAExB;IAEF;;;;OAIG;IACI,MAAM,OAAQ,MAAM,gBAKzB;IAEF,MAAM;CAsDT;AAED,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"NotificationManager.d.ts","sourceRoot":"","sources":["../../../src/components/Notification/NotificationManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,OAAO,EAAE,qBAAqB,EAAqB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAExF,UAAU,wBAAwB;IAE9B,QAAQ,EAAE,qBAAqB,CAAC;IAEhC,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,UAAU,UAAW,SAAQ,mBAAmB;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAGD,UAAU,wBAAwB;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;CACzB;AAQD;;GAEG;AACH,cAAM,mBAAoB,SAAQ,KAAK,CAAC,SAAS,CAC7C,wBAAwB,EACxB,wBAAwB,CAC3B;IACG,KAAK,EAAE,wBAAwB,CAE7B;IAGF,OAAO,CAAC,QAAQ,CAAgB;IAGhC,OAAO,CAAC,GAAG,CAAqB;IAGhC,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,kBAAkB,CAAqC;IAE/D;;;;OAIG;IACI,MAAM,OAAQ,MAAM,UAsCzB;IAEF;;;;OAIG;IACI,GAAG,WAAkB,mBAAmB,qBAyC7C;IAEF;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAWtB;IAEF;;;;OAIG;IACI,iBAAiB,OAAQ,MAAM,gBAEpC;IAEF;;;;OAIG;IACI,KAAK,OAAQ,MAAM,gBAExB;IAEF;;;;OAIG;IACI,MAAM,OAAQ,MAAM,gBAKzB;IAEF,MAAM;CA+ET;AAED,eAAe,mBAAmB,CAAC"}
@@ -1,8 +1,17 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
11
  import React from 'react';
3
12
  import { Close, Info, ReportProblem, ErrorOutline, CheckCircle } from '../../icons';
4
13
  import { ActionButton } from '../Button';
5
- import { Container, Notice, Title, IconContainer, FillParent, Body, CloseButton, Footer, } from './style';
14
+ import { Container, Notice, Title, IconContainer, FillParent, Body, CloseButton, Footer, VisuallyHidden, } from './style';
6
15
  import { NOTIFICATION_TYPE } from './types';
7
16
  const DEFAULT_DURATION = 5000;
8
17
  /**
@@ -18,6 +27,9 @@ class NotificationManager extends React.Component {
18
27
  this.timeouts = {};
19
28
  // Set of notification ids
20
29
  this.set = new Set();
30
+ // Refs for live regions to ensure they exist before updates
31
+ this.politeRegionRef = React.createRef();
32
+ this.assertiveRegionRef = React.createRef();
21
33
  /**
22
34
  * Removes a notification from stack if the notification with the given id is found.
23
35
  *
@@ -60,17 +72,23 @@ class NotificationManager extends React.Component {
60
72
  *
61
73
  * @param notice
62
74
  */
63
- this.add = (notice) => {
75
+ this.add = (notice) => __awaiter(this, void 0, void 0, function* () {
64
76
  // Generate unique id if not provided.
65
77
  const id = notice.id || (Math.random() * Math.pow(10, 7)).toFixed(0);
66
78
  // De-dupe on id
67
79
  if (!this.set.has(id)) {
80
+ const type = notice.type || NOTIFICATION_TYPE.INFO;
81
+ const isUrgent = type === NOTIFICATION_TYPE.WARNING || type === NOTIFICATION_TYPE.DANGER;
68
82
  // Add notice to the top of stack.
69
83
  this.setState({
70
84
  notices: [
71
85
  Object.assign(Object.assign({}, notice), { id }),
72
86
  ...this.state.notices,
73
87
  ],
88
+ }, () => {
89
+ // Update live region after state update
90
+ const announcement = `${notice.title} ${notice.description}`;
91
+ this.updateLiveRegion(announcement, isUrgent);
74
92
  });
75
93
  // set timeout for closing the notification.
76
94
  if (!notice.sticky) {
@@ -80,6 +98,23 @@ class NotificationManager extends React.Component {
80
98
  this.set.add(id);
81
99
  }
82
100
  return id;
101
+ });
102
+ /**
103
+ * Update live region content with clear-then-set pattern for reliable VoiceOver announcements.
104
+ *
105
+ * @param content - The text content to announce
106
+ * @param isAssertive - Whether to use assertive (alert) or polite (log) live region
107
+ */
108
+ this.updateLiveRegion = (content, isAssertive) => {
109
+ const region = isAssertive ? this.assertiveRegionRef.current : this.politeRegionRef.current;
110
+ if (region) {
111
+ // Add content after delay
112
+ setTimeout(() => {
113
+ if (region) {
114
+ region.textContent = content;
115
+ }
116
+ }, 150);
117
+ }
83
118
  };
84
119
  /**
85
120
  * Handler for close button click.
@@ -110,12 +145,12 @@ class NotificationManager extends React.Component {
110
145
  };
111
146
  }
112
147
  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: () => {
116
- buttonClick === null || buttonClick === void 0 ? void 0 : buttonClick();
117
- }, children: buttonText }) }))] })] }), id));
118
- }) }));
148
+ return (_jsxs(Container, { position: this.props.position, children: [_jsx(VisuallyHidden, { ref: this.politeRegionRef, role: "log", "aria-live": "polite", "aria-atomic": "false", "aria-relevant": "additions text" }), _jsx(VisuallyHidden, { ref: this.assertiveRegionRef, role: "alert", "aria-live": "assertive", "aria-atomic": "true" }), _jsx("div", { role: "list", "aria-label": this.props.ariaLabel, children: this.state.notices.map((notice) => {
149
+ const { id, title, description, leaving, type = NOTIFICATION_TYPE.INFO, buttonText, buttonClick, closeButtonAriaLabel, } = notice;
150
+ return (_jsxs(Notice, Object.assign({}, notice, { position: this.props.position, className: leaving ? 'leave' : '', onMouseEnter: this.pause(id), onMouseLeave: this.resume(id), role: "listitem", children: [_jsxs(IconContainer, { type: type, "aria-hidden": "true", 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: [_jsx(Title, { type: type, children: title }), _jsx(Body, { children: description }), buttonText && (_jsx(Footer, { children: _jsx(ActionButton, { onClick: () => {
151
+ buttonClick === null || buttonClick === void 0 ? void 0 : buttonClick();
152
+ }, children: buttonText }) }))] }), _jsx(CloseButton, { onClick: this.closeClickHandler(id), "aria-label": closeButtonAriaLabel || 'Close notification', tabIndex: 0, children: _jsx(Close, {}) })] }), id));
153
+ }) })] }));
119
154
  }
120
155
  }
121
156
  export default NotificationManager;
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationManager.js","sourceRoot":"","sources":["../../../src/components/Notification/NotificationManager.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Close, Info, ReportProblem, ErrorOutline, CheckCircle } from '../../icons';\nimport { ActionButton } from '../Button';\nimport {\n Container,\n Notice,\n Title,\n IconContainer,\n FillParent,\n Body,\n CloseButton,\n Footer,\n} from './style';\nimport { NOTIFICATION_POSITION, NOTIFICATION_TYPE, NotificationOptions } from './types';\n\ninterface NotificationManagerProps {\n // Notification Position\n position: NOTIFICATION_POSITION;\n // Callback for when stack is emptied\n onEmpty: () => void;\n}\n\n// Notice prop\ninterface NoticeProp extends NotificationOptions {\n leaving?: boolean;\n}\n\n// Manager state\ninterface NotificationManagerState {\n notices: NoticeProp[];\n}\n\ntype timeouts = {\n [id: string]: NodeJS.Timeout;\n};\n\nconst DEFAULT_DURATION = 5000;\n\n/**\n * Notification Manager class\n */\nclass NotificationManager extends React.Component<\n NotificationManagerProps,\n NotificationManagerState\n> {\n state: NotificationManagerState = {\n notices: [],\n };\n\n // bookkeeping for timeouts\n private timeouts: timeouts = {};\n\n // Set of notification ids\n private set = new Set<string>();\n\n /**\n * Removes a notification from stack if the notification with the given id is found.\n *\n * @param id\n */\n public remove = (id: string) => {\n // Trigger leaving animation.\n this.setState({\n notices: this.state.notices.map((notice) => ({\n ...notice,\n leaving: notice.id === id ? true : notice.leaving,\n })),\n });\n this.set.delete(id);\n\n // Remove notification on animation completion.\n setTimeout(() => {\n const notice = this.state.notices.find((notice) => notice.id === id);\n if (notice) {\n // call close callback, ignore any errors in callback.\n if (notice.onClose) {\n try {\n notice.onClose();\n } catch (e) {\n console.warn('Error in notification close callback', e.message);\n }\n }\n\n // Remove the notification\n this.setState(\n {\n notices: this.state.notices.filter((notice) => notice.id !== id),\n },\n () => {\n // Check if the stack is empty and then call the\n // empty callback function.\n if (this.state.notices.length === 0) {\n this.props.onEmpty();\n }\n },\n );\n }\n }, 550);\n };\n\n /**\n * Adds a notification to stack.\n *\n * @param notice\n */\n public add = (notice: NotificationOptions) => {\n // Generate unique id if not provided.\n const id = notice.id || (Math.random() * 10 ** 7).toFixed(0);\n\n // De-dupe on id\n if (!this.set.has(id)) {\n // Add notice to the top of stack.\n this.setState({\n notices: [\n {\n ...notice,\n id,\n },\n ...this.state.notices,\n ],\n });\n\n // set timeout for closing the notification.\n if (!notice.sticky) {\n this.timeouts[id] = setTimeout(\n () => this.remove(id),\n notice.duration || DEFAULT_DURATION,\n );\n }\n\n // Add id to the set.\n this.set.add(id);\n }\n\n return id;\n };\n\n /**\n * Handler for close button click.\n *\n * @param id\n */\n public closeClickHandler = (id: string) => () => {\n this.remove(id);\n };\n\n /**\n * Pause notification when user is hovering over it.\n *\n * @param id\n */\n public pause = (id: string) => () => {\n clearTimeout(this.timeouts[id]);\n };\n\n /**\n * Restart the removal of notification.\n *\n * @param id\n */\n public resume = (id: string) => () => {\n const notice = this.state.notices.find((notice) => notice.id === id);\n if (!notice.sticky) {\n this.timeouts[id] = setTimeout(() => this.remove(id), DEFAULT_DURATION);\n }\n };\n\n render() {\n return (\n <Container position={this.props.position}>\n {this.state.notices.map((notice) => {\n const {\n id,\n title,\n description,\n leaving,\n type = NOTIFICATION_TYPE.INFO,\n buttonText,\n buttonClick,\n } = notice;\n return (\n <Notice\n key={id}\n {...notice}\n position={this.props.position}\n className={leaving ? 'leave' : ''}\n onMouseEnter={this.pause(id)}\n onMouseLeave={this.resume(id)}\n >\n <IconContainer type={type}>\n {type === NOTIFICATION_TYPE.INFO && <Info />}\n {type === NOTIFICATION_TYPE.SUCCESS && <CheckCircle />}\n {type === NOTIFICATION_TYPE.WARNING && <ReportProblem />}\n {type === NOTIFICATION_TYPE.DANGER && <ErrorOutline />}\n </IconContainer>\n <FillParent>\n <Title type={type}>\n <FillParent>{title}</FillParent>\n <CloseButton onClick={this.closeClickHandler(id)}>\n <Close />\n </CloseButton>\n </Title>\n <Body>{description}</Body>\n {buttonText && (\n <Footer>\n <ActionButton\n onClick={() => {\n buttonClick?.();\n }}\n >\n {buttonText}\n </ActionButton>\n </Footer>\n )}\n </FillParent>\n </Notice>\n );\n })}\n </Container>\n );\n }\n}\n\nexport default NotificationManager;\n"]}
1
+ {"version":3,"file":"NotificationManager.js","sourceRoot":"","sources":["../../../src/components/Notification/NotificationManager.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EACH,SAAS,EACT,MAAM,EACN,KAAK,EACL,aAAa,EACb,UAAU,EACV,IAAI,EACJ,WAAW,EACX,MAAM,EACN,cAAc,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAyB,iBAAiB,EAAuB,MAAM,SAAS,CAAC;AAyBxF,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B;;GAEG;AACH,MAAM,mBAAoB,SAAQ,KAAK,CAAC,SAGvC;IAHD;;QAII,UAAK,GAA6B;YAC9B,OAAO,EAAE,EAAE;SACd,CAAC;QAEF,2BAA2B;QACnB,aAAQ,GAAa,EAAE,CAAC;QAEhC,0BAA0B;QAClB,QAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAEhC,4DAA4D;QACpD,oBAAe,GAAG,KAAK,CAAC,SAAS,EAAkB,CAAC;QACpD,uBAAkB,GAAG,KAAK,CAAC,SAAS,EAAkB,CAAC;QAE/D;;;;WAIG;QACI,WAAM,GAAG,CAAC,EAAU,EAAE,EAAE;YAC3B,6BAA6B;YAC7B,IAAI,CAAC,QAAQ,CAAC;gBACV,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,iCACrC,MAAM,KACT,OAAO,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,IACnD,CAAC;aACN,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAEpB,+CAA+C;YAC/C,UAAU,CAAC,GAAG,EAAE;gBACZ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;gBACrE,IAAI,MAAM,EAAE,CAAC;oBACT,sDAAsD;oBACtD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBACjB,IAAI,CAAC;4BACD,MAAM,CAAC,OAAO,EAAE,CAAC;wBACrB,CAAC;wBAAC,OAAO,CAAC,EAAE,CAAC;4BACT,OAAO,CAAC,IAAI,CAAC,sCAAsC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;wBACpE,CAAC;oBACL,CAAC;oBAED,0BAA0B;oBAC1B,IAAI,CAAC,QAAQ,CACT;wBACI,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;qBACnE,EACD,GAAG,EAAE;wBACD,gDAAgD;wBAChD,2BAA2B;wBAC3B,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAClC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;wBACzB,CAAC;oBACL,CAAC,CACJ,CAAC;gBACN,CAAC;YACL,CAAC,EAAE,GAAG,CAAC,CAAC;QACZ,CAAC,CAAC;QAEF;;;;WAIG;QACI,QAAG,GAAG,CAAO,MAA2B,EAAE,EAAE;YAC/C,sCAAsC;YACtC,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAA,EAAE,EAAI,CAAC,CAAA,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAE7D,gBAAgB;YAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,iBAAiB,CAAC,IAAI,CAAC;gBACnD,MAAM,QAAQ,GACV,IAAI,KAAK,iBAAiB,CAAC,OAAO,IAAI,IAAI,KAAK,iBAAiB,CAAC,MAAM,CAAC;gBAE5E,kCAAkC;gBAClC,IAAI,CAAC,QAAQ,CACT;oBACI,OAAO,EAAE;wDAEE,MAAM,KACT,EAAE;wBAEN,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO;qBACxB;iBACJ,EACD,GAAG,EAAE;oBACD,wCAAwC;oBACxC,MAAM,YAAY,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;oBAC7D,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;gBAClD,CAAC,CACJ,CAAC;gBAEF,4CAA4C;gBAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;oBACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,UAAU,CAC1B,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EACrB,MAAM,CAAC,QAAQ,IAAI,gBAAgB,CACtC,CAAC;gBACN,CAAC;gBAED,qBAAqB;gBACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC;YAED,OAAO,EAAE,CAAC;QACd,CAAC,CAAA,CAAC;QAEF;;;;;WAKG;QACK,qBAAgB,GAAG,CAAC,OAAe,EAAE,WAAoB,EAAE,EAAE;YACjE,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;YAE5F,IAAI,MAAM,EAAE,CAAC;gBACT,0BAA0B;gBAC1B,UAAU,CAAC,GAAG,EAAE;oBACZ,IAAI,MAAM,EAAE,CAAC;wBACT,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC;oBACjC,CAAC;gBACL,CAAC,EAAE,GAAG,CAAC,CAAC;YACZ,CAAC;QACL,CAAC,CAAC;QAEF;;;;WAIG;QACI,sBAAiB,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,EAAE;YAC5C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC,CAAC;QAEF;;;;WAIG;QACI,UAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,EAAE;YAChC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC;QAEF;;;;WAIG;QACI,WAAM,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,EAAE;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC;YAC5E,CAAC;QACL,CAAC,CAAC;IAiFN,CAAC;IA/EG,MAAM;QACF,OAAO,CACH,MAAC,SAAS,IAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,aAEpC,KAAC,cAAc,IACX,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,IAAI,EAAC,KAAK,eACA,QAAQ,iBACN,OAAO,mBACL,gBAAgB,GAChC,EAGF,KAAC,cAAc,IACX,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAC5B,IAAI,EAAC,OAAO,eACF,WAAW,iBACT,MAAM,GACpB,EAGF,cAAK,IAAI,EAAC,MAAM,gBAAa,IAAI,CAAC,KAAK,CAAC,SAAS,YAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;wBAC/B,MAAM,EACF,EAAE,EACF,KAAK,EACL,WAAW,EACX,OAAO,EACP,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAC7B,UAAU,EACV,WAAW,EACX,oBAAoB,GACvB,GAAG,MAAM,CAAC;wBAEX,OAAO,CACH,MAAC,MAAM,oBAEC,MAAM,IACV,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAC7B,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EACjC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAC5B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAC7B,IAAI,EAAC,UAAU,aAEf,MAAC,aAAa,IAAC,IAAI,EAAE,IAAI,iBAAc,MAAM,aACxC,IAAI,KAAK,iBAAiB,CAAC,IAAI,IAAI,KAAC,IAAI,KAAG,EAC3C,IAAI,KAAK,iBAAiB,CAAC,OAAO,IAAI,KAAC,WAAW,KAAG,EACrD,IAAI,KAAK,iBAAiB,CAAC,OAAO,IAAI,KAAC,aAAa,KAAG,EACvD,IAAI,KAAK,iBAAiB,CAAC,MAAM,IAAI,KAAC,YAAY,KAAG,IAC1C,EAChB,MAAC,UAAU,eACP,KAAC,KAAK,IAAC,IAAI,EAAE,IAAI,YAAG,KAAK,GAAS,EAClC,KAAC,IAAI,cAAE,WAAW,GAAQ,EACzB,UAAU,IAAI,CACX,KAAC,MAAM,cACH,KAAC,YAAY,IACT,OAAO,EAAE,GAAG,EAAE;oDACV,WAAW,aAAX,WAAW,uBAAX,WAAW,EAAI,CAAC;gDACpB,CAAC,YAEA,UAAU,GACA,GACV,CACZ,IACQ,EACb,KAAC,WAAW,IACR,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,gBACvB,oBAAoB,IAAI,oBAAoB,EACxD,QAAQ,EAAE,CAAC,YAEX,KAAC,KAAK,KAAG,GACC,MAnCT,EAAE,CAoCF,CACZ,CAAC;oBACN,CAAC,CAAC,GACA,IACE,CACf,CAAC;IACN,CAAC;CACJ;AAED,eAAe,mBAAmB,CAAC","sourcesContent":["import React from 'react';\nimport { Close, Info, ReportProblem, ErrorOutline, CheckCircle } from '../../icons';\nimport { ActionButton } from '../Button';\nimport {\n Container,\n Notice,\n Title,\n IconContainer,\n FillParent,\n Body,\n CloseButton,\n Footer,\n VisuallyHidden,\n} from './style';\nimport { NOTIFICATION_POSITION, NOTIFICATION_TYPE, NotificationOptions } from './types';\n\ninterface NotificationManagerProps {\n // Notification Position\n position: NOTIFICATION_POSITION;\n // Callback for when stack is emptied\n onEmpty: () => void;\n // Aria label for the notification list\n ariaLabel?: string;\n}\n\n// Notice prop\ninterface NoticeProp extends NotificationOptions {\n leaving?: boolean;\n}\n\n// Manager state\ninterface NotificationManagerState {\n notices: NoticeProp[];\n}\n\ntype timeouts = {\n [id: string]: NodeJS.Timeout;\n};\n\nconst DEFAULT_DURATION = 5000;\n\n/**\n * Notification Manager class\n */\nclass NotificationManager extends React.Component<\n NotificationManagerProps,\n NotificationManagerState\n> {\n state: NotificationManagerState = {\n notices: [],\n };\n\n // bookkeeping for timeouts\n private timeouts: timeouts = {};\n\n // Set of notification ids\n private set = new Set<string>();\n\n // Refs for live regions to ensure they exist before updates\n private politeRegionRef = React.createRef<HTMLDivElement>();\n private assertiveRegionRef = React.createRef<HTMLDivElement>();\n\n /**\n * Removes a notification from stack if the notification with the given id is found.\n *\n * @param id\n */\n public remove = (id: string) => {\n // Trigger leaving animation.\n this.setState({\n notices: this.state.notices.map((notice) => ({\n ...notice,\n leaving: notice.id === id ? true : notice.leaving,\n })),\n });\n this.set.delete(id);\n\n // Remove notification on animation completion.\n setTimeout(() => {\n const notice = this.state.notices.find((notice) => notice.id === id);\n if (notice) {\n // call close callback, ignore any errors in callback.\n if (notice.onClose) {\n try {\n notice.onClose();\n } catch (e) {\n console.warn('Error in notification close callback', e.message);\n }\n }\n\n // Remove the notification\n this.setState(\n {\n notices: this.state.notices.filter((notice) => notice.id !== id),\n },\n () => {\n // Check if the stack is empty and then call the\n // empty callback function.\n if (this.state.notices.length === 0) {\n this.props.onEmpty();\n }\n },\n );\n }\n }, 550);\n };\n\n /**\n * Adds a notification to stack.\n *\n * @param notice\n */\n public add = async (notice: NotificationOptions) => {\n // Generate unique id if not provided.\n const id = notice.id || (Math.random() * 10 ** 7).toFixed(0);\n\n // De-dupe on id\n if (!this.set.has(id)) {\n const type = notice.type || NOTIFICATION_TYPE.INFO;\n const isUrgent =\n type === NOTIFICATION_TYPE.WARNING || type === NOTIFICATION_TYPE.DANGER;\n\n // Add notice to the top of stack.\n this.setState(\n {\n notices: [\n {\n ...notice,\n id,\n },\n ...this.state.notices,\n ],\n },\n () => {\n // Update live region after state update\n const announcement = `${notice.title} ${notice.description}`;\n this.updateLiveRegion(announcement, isUrgent);\n },\n );\n\n // set timeout for closing the notification.\n if (!notice.sticky) {\n this.timeouts[id] = setTimeout(\n () => this.remove(id),\n notice.duration || DEFAULT_DURATION,\n );\n }\n\n // Add id to the set.\n this.set.add(id);\n }\n\n return id;\n };\n\n /**\n * Update live region content with clear-then-set pattern for reliable VoiceOver announcements.\n *\n * @param content - The text content to announce\n * @param isAssertive - Whether to use assertive (alert) or polite (log) live region\n */\n private updateLiveRegion = (content: string, isAssertive: boolean) => {\n const region = isAssertive ? this.assertiveRegionRef.current : this.politeRegionRef.current;\n\n if (region) {\n // Add content after delay\n setTimeout(() => {\n if (region) {\n region.textContent = content;\n }\n }, 150);\n }\n };\n\n /**\n * Handler for close button click.\n *\n * @param id\n */\n public closeClickHandler = (id: string) => () => {\n this.remove(id);\n };\n\n /**\n * Pause notification when user is hovering over it.\n *\n * @param id\n */\n public pause = (id: string) => () => {\n clearTimeout(this.timeouts[id]);\n };\n\n /**\n * Restart the removal of notification.\n *\n * @param id\n */\n public resume = (id: string) => () => {\n const notice = this.state.notices.find((notice) => notice.id === id);\n if (!notice.sticky) {\n this.timeouts[id] = setTimeout(() => this.remove(id), DEFAULT_DURATION);\n }\n };\n\n render() {\n return (\n <Container position={this.props.position}>\n {/* Polite live region - uses role=\"log\" for better VoiceOver compatibility */}\n <VisuallyHidden\n ref={this.politeRegionRef}\n role=\"log\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n aria-relevant=\"additions text\"\n />\n\n {/* Assertive live region - pre-rendered and persistent */}\n <VisuallyHidden\n ref={this.assertiveRegionRef}\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n />\n\n {/* Visual notifications with list semantics */}\n <div role=\"list\" aria-label={this.props.ariaLabel}>\n {this.state.notices.map((notice) => {\n const {\n id,\n title,\n description,\n leaving,\n type = NOTIFICATION_TYPE.INFO,\n buttonText,\n buttonClick,\n closeButtonAriaLabel,\n } = notice;\n\n return (\n <Notice\n key={id}\n {...notice}\n position={this.props.position}\n className={leaving ? 'leave' : ''}\n onMouseEnter={this.pause(id)}\n onMouseLeave={this.resume(id)}\n role=\"listitem\"\n >\n <IconContainer type={type} aria-hidden=\"true\">\n {type === NOTIFICATION_TYPE.INFO && <Info />}\n {type === NOTIFICATION_TYPE.SUCCESS && <CheckCircle />}\n {type === NOTIFICATION_TYPE.WARNING && <ReportProblem />}\n {type === NOTIFICATION_TYPE.DANGER && <ErrorOutline />}\n </IconContainer>\n <FillParent>\n <Title type={type}>{title}</Title>\n <Body>{description}</Body>\n {buttonText && (\n <Footer>\n <ActionButton\n onClick={() => {\n buttonClick?.();\n }}\n >\n {buttonText}\n </ActionButton>\n </Footer>\n )}\n </FillParent>\n <CloseButton\n onClick={this.closeClickHandler(id)}\n aria-label={closeButtonAriaLabel || 'Close notification'}\n tabIndex={0}\n >\n <Close />\n </CloseButton>\n </Notice>\n );\n })}\n </div>\n </Container>\n );\n }\n}\n\nexport default NotificationManager;\n"]}
@@ -42,5 +42,9 @@ export declare const Footer: import("@emotion/styled").StyledComponent<{
42
42
  theme?: import("@emotion/react").Theme;
43
43
  as?: React.ElementType;
44
44
  }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
45
+ export declare const VisuallyHidden: import("@emotion/styled").StyledComponent<{
46
+ theme?: import("@emotion/react").Theme;
47
+ as?: React.ElementType;
48
+ }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {}>;
45
49
  export {};
46
50
  //# sourceMappingURL=style.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../src/components/Notification/style.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AA6DxF,UAAU,UAAW,SAAQ,mBAAmB;IAC5C,QAAQ,EAAE,qBAAqB,CAAC;CACnC;AAED,eAAO,MAAM,SAAS;;SAlDd,MAAK,WAAU;;cAkDyB,qBAAqB;yGAOpE,CAAC;AAEF,eAAO,MAAM,MAAM;;SA3DX,MAAK,WAAU;;;uBAsItB,CAAC;AAEF,eAAO,MAAM,KAAK;;SAxIV,MAAK,WAAU;;UAwIiB,iBAAiB;yGAMxD,CAAC;AAEF,eAAO,MAAM,UAAU;;SAhJf,MAAK,WAAU;yGAkJtB,CAAC;AAEF,eAAO,MAAM,WAAW;;SApJhB,MAAK,WAAU;qHA8JtB,CAAC;AAEF,eAAO,MAAM,IAAI;;SAhKT,MAAK,WAAU;yGAmKtB,CAAC;AAEF,eAAO,MAAM,aAAa;;SArKlB,MAAK,WAAU;;UAqKyB,iBAAiB;yGAGhE,CAAC;AAEF,eAAO,MAAM,MAAM;;SA1KX,MAAK,WAAU;yGA8KtB,CAAC"}
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../src/components/Notification/style.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AA6DxF,UAAU,UAAW,SAAQ,mBAAmB;IAC5C,QAAQ,EAAE,qBAAqB,CAAC;CACnC;AAED,eAAO,MAAM,SAAS;;SAnDQ,MAAO,WAClC;;cAkD6C,qBAAqB;yGAOpE,CAAC;AAEF,eAAO,MAAM,MAAM;;SA5DW,MAAO,WAClC;;;uBAuIF,CAAC;AAEF,eAAO,MAAM,KAAK;;SA1IY,MAAO,WAClC;;UAyIqC,iBAAiB;yGAMxD,CAAC;AAEF,eAAO,MAAM,UAAU;;SAlJO,MAAO,WAClC;yGAmJF,CAAC;AAEF,eAAO,MAAM,WAAW;;SAtJM,MAAO,WAClC;qHAkKF,CAAC;AAEF,eAAO,MAAM,IAAI;;SArKa,MAAO,WAClC;yGAuKF,CAAC;AAEF,eAAO,MAAM,aAAa;;SA1KI,MAAO,WAClC;;UAyK6C,iBAAiB;yGAGhE,CAAC;AAEF,eAAO,MAAM,MAAM;;SA/KW,MAAO,WAClC;yGAkLF,CAAC;AAEF,eAAO,MAAM,cAAc;;SArLG,MAAO,WAClC;2GA8LF,CAAC"}