@mezzanine-ui/react 1.0.0-rc.5 → 1.0.0-rc.7

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 (213) hide show
  1. package/Accordion/Accordion.d.ts +36 -0
  2. package/Accordion/Accordion.js +37 -1
  3. package/AlertBanner/AlertBanner.d.ts +30 -1
  4. package/AlertBanner/AlertBanner.js +56 -12
  5. package/AutoComplete/AutoComplete.d.ts +75 -11
  6. package/AutoComplete/AutoComplete.js +145 -25
  7. package/AutoComplete/AutoCompleteInside.d.ts +54 -0
  8. package/AutoComplete/AutoCompleteInside.js +17 -0
  9. package/AutoComplete/useAutoCompleteKeyboard.d.ts +2 -1
  10. package/AutoComplete/useAutoCompleteKeyboard.js +4 -1
  11. package/Backdrop/Backdrop.d.ts +33 -1
  12. package/Backdrop/Backdrop.js +33 -1
  13. package/Badge/Badge.d.ts +26 -1
  14. package/Badge/Badge.js +26 -1
  15. package/Badge/typings.d.ts +15 -0
  16. package/Breadcrumb/BreadcrumbDropdown.d.ts +1 -1
  17. package/Breadcrumb/BreadcrumbOverflowMenuDropdown.d.ts +1 -1
  18. package/Breadcrumb/typings.d.ts +1 -1
  19. package/Button/Button.d.ts +26 -1
  20. package/Button/Button.js +33 -5
  21. package/COMPONENTS.md +267 -0
  22. package/Calendar/useCalendarControls.d.ts +18 -0
  23. package/Calendar/useCalendarControls.js +18 -0
  24. package/Card/FourThumbnailCard.js +1 -1
  25. package/Card/SingleThumbnailCard.js +1 -1
  26. package/Checkbox/Checkbox.d.ts +30 -1
  27. package/Checkbox/Checkbox.js +54 -4
  28. package/Checkbox/CheckboxGroup.d.ts +39 -1
  29. package/Checkbox/CheckboxGroup.js +49 -3
  30. package/Cropper/Cropper.d.ts +2 -2
  31. package/Cropper/Cropper.js +2 -3
  32. package/Cropper/CropperElement.js +1 -1
  33. package/Cropper/utils/cropper-calculations.d.ts +1 -1
  34. package/Cropper/utils/cropper-calculations.js +16 -14
  35. package/DatePicker/DatePicker.d.ts +36 -2
  36. package/DatePicker/DatePicker.js +36 -2
  37. package/DateRangePicker/useDateRangePickerValue.d.ts +24 -0
  38. package/DateRangePicker/useDateRangePickerValue.js +24 -0
  39. package/Description/Description.d.ts +1 -1
  40. package/Description/Description.js +1 -1
  41. package/Description/DescriptionTitle.d.ts +6 -1
  42. package/Description/DescriptionTitle.js +2 -2
  43. package/Drawer/Drawer.d.ts +78 -33
  44. package/Drawer/Drawer.js +72 -34
  45. package/Dropdown/Dropdown.d.ts +63 -1
  46. package/Dropdown/Dropdown.js +203 -9
  47. package/Dropdown/DropdownItem.d.ts +26 -2
  48. package/Dropdown/DropdownItem.js +91 -43
  49. package/Dropdown/DropdownItemCard.d.ts +3 -2
  50. package/Dropdown/DropdownItemCard.js +8 -5
  51. package/Dropdown/DropdownStatus.d.ts +2 -2
  52. package/Dropdown/DropdownStatus.js +3 -2
  53. package/Dropdown/dropdownKeydownHandler.d.ts +6 -0
  54. package/Dropdown/dropdownKeydownHandler.js +14 -7
  55. package/Empty/icons/EmptyMainInitialDataIcon.js +1 -1
  56. package/Empty/icons/EmptyMainNotificationIcon.js +1 -1
  57. package/Empty/icons/EmptyMainResultIcon.js +1 -1
  58. package/Empty/icons/EmptyMainSystemIcon.js +1 -1
  59. package/FilterArea/Filter.d.ts +25 -2
  60. package/FilterArea/Filter.js +43 -2
  61. package/FilterArea/FilterArea.d.ts +43 -4
  62. package/FilterArea/FilterArea.js +39 -4
  63. package/FilterArea/FilterAreaContext.d.ts +6 -0
  64. package/FilterArea/FilterAreaContext.js +6 -0
  65. package/FilterArea/FilterLine.d.ts +19 -0
  66. package/FilterArea/FilterLine.js +19 -0
  67. package/FilterArea/index.d.ts +2 -2
  68. package/FilterArea/index.js +1 -1
  69. package/Form/FormField.d.ts +43 -2
  70. package/Form/FormField.js +40 -3
  71. package/Form/typings.d.ts +2 -0
  72. package/Form/useAutoCompleteValueControl.d.ts +20 -0
  73. package/Form/useAutoCompleteValueControl.js +20 -0
  74. package/Form/useCheckboxControlValue.d.ts +19 -0
  75. package/Form/useCheckboxControlValue.js +19 -0
  76. package/Form/useControlValueState.d.ts +16 -0
  77. package/Form/useControlValueState.js +16 -0
  78. package/Form/useCustomControlValue.d.ts +17 -0
  79. package/Form/useCustomControlValue.js +17 -0
  80. package/Form/useInputControlValue.d.ts +19 -0
  81. package/Form/useInputControlValue.js +19 -0
  82. package/Form/useInputWithClearControlValue.d.ts +20 -0
  83. package/Form/useInputWithClearControlValue.js +20 -0
  84. package/Form/useRadioControlValue.d.ts +19 -0
  85. package/Form/useRadioControlValue.js +19 -0
  86. package/Form/useSelectValueControl.d.ts +19 -0
  87. package/Form/useSelectValueControl.js +19 -0
  88. package/Form/useSwitchControlValue.d.ts +18 -0
  89. package/Form/useSwitchControlValue.js +18 -0
  90. package/Icon/Icon.d.ts +23 -1
  91. package/Icon/Icon.js +23 -1
  92. package/Input/Input.d.ts +31 -1
  93. package/Input/Input.js +31 -1
  94. package/Input/SpinnerButton/SpinnerButton.js +1 -1
  95. package/Message/Message.d.ts +56 -6
  96. package/Message/Message.js +59 -52
  97. package/Modal/Modal.d.ts +76 -4
  98. package/Modal/Modal.js +117 -6
  99. package/Modal/ModalBodyForVerification.js +3 -1
  100. package/Modal/ModalFooter.d.ts +21 -6
  101. package/Modal/ModalHeader.d.ts +50 -11
  102. package/Modal/ModalHeader.js +1 -1
  103. package/Modal/index.d.ts +1 -1
  104. package/Navigation/Navigation.js +20 -11
  105. package/Navigation/NavigationHeader.js +2 -1
  106. package/Navigation/NavigationIconButton.d.ts +8 -0
  107. package/Navigation/NavigationIconButton.js +2 -2
  108. package/Navigation/NavigationOption.js +6 -3
  109. package/Navigation/NavigationOverflowMenu.js +9 -6
  110. package/Navigation/NavigationUserMenu.js +3 -1
  111. package/Navigation/context.d.ts +1 -0
  112. package/NotificationCenter/NotificationCenter.d.ts +59 -9
  113. package/NotificationCenter/NotificationCenter.js +150 -54
  114. package/NotificationCenter/NotificationCenterDrawer.d.ts +56 -6
  115. package/NotificationCenter/NotificationCenterDrawer.js +6 -8
  116. package/NotificationCenter/index.d.ts +1 -1
  117. package/OverflowTooltip/OverflowTooltip.js +46 -5
  118. package/PageFooter/PageFooter.d.ts +1 -1
  119. package/PageFooter/PageFooter.js +8 -16
  120. package/Pagination/Pagination.d.ts +38 -1
  121. package/Pagination/Pagination.js +38 -1
  122. package/Pagination/PaginationPageSize.js +1 -1
  123. package/Pagination/usePagination.d.ts +20 -0
  124. package/Pagination/usePagination.js +20 -0
  125. package/Progress/Progress.d.ts +24 -1
  126. package/Progress/Progress.js +24 -1
  127. package/README.md +82 -0
  128. package/Radio/Radio.d.ts +35 -1
  129. package/Radio/Radio.js +50 -12
  130. package/Radio/RadioGroup.d.ts +2 -2
  131. package/Radio/RadioGroupContext.d.ts +3 -2
  132. package/Section/SectionGroup.d.ts +20 -0
  133. package/Section/SectionGroup.js +16 -0
  134. package/Section/index.d.ts +2 -0
  135. package/Section/index.js +1 -0
  136. package/Select/Select.d.ts +55 -1
  137. package/Select/Select.js +37 -2
  138. package/Select/typings.d.ts +9 -0
  139. package/{Selection/Selection.d.ts → SelectionCard/SelectionCard.d.ts} +23 -11
  140. package/{Selection/Selection.js → SelectionCard/SelectionCard.js} +14 -14
  141. package/SelectionCard/SelectionCardGroup.d.ts +28 -0
  142. package/SelectionCard/index.d.ts +12 -0
  143. package/SelectionCard/index.js +5 -0
  144. package/Separator/Separator.d.ts +19 -1
  145. package/Separator/Separator.js +19 -1
  146. package/Slider/Slider.d.ts +11 -0
  147. package/Slider/useSlider.d.ts +21 -0
  148. package/Spin/Spin.d.ts +14 -5
  149. package/Spin/Spin.js +6 -8
  150. package/Stepper/Stepper.d.ts +34 -1
  151. package/Stepper/Stepper.js +34 -1
  152. package/Stepper/useStepper.d.ts +18 -0
  153. package/Stepper/useStepper.js +18 -0
  154. package/Tab/Tab.d.ts +33 -1
  155. package/Tab/Tab.js +33 -1
  156. package/Table/Table.d.ts +51 -3
  157. package/Table/Table.js +52 -4
  158. package/Table/hooks/useTableDataSource.d.ts +4 -4
  159. package/Table/hooks/useTableDataSource.js +1 -1
  160. package/Tag/Tag.d.ts +27 -1
  161. package/Tag/Tag.js +27 -1
  162. package/Tag/typings.d.ts +28 -0
  163. package/Textarea/Textarea.d.ts +28 -1
  164. package/Textarea/Textarea.js +25 -1
  165. package/TimePicker/TimePicker.js +1 -1
  166. package/TimeRangePicker/TimeRangePicker.js +1 -1
  167. package/Toggle/Toggle.d.ts +34 -1
  168. package/Toggle/Toggle.js +34 -1
  169. package/Tooltip/Tooltip.d.ts +39 -1
  170. package/Tooltip/Tooltip.js +39 -1
  171. package/Tooltip/useDelayMouseEnterLeave.d.ts +17 -0
  172. package/Tooltip/useDelayMouseEnterLeave.js +17 -0
  173. package/Typography/Typography.d.ts +23 -1
  174. package/Typography/Typography.js +23 -1
  175. package/Upload/Upload.d.ts +13 -7
  176. package/Upload/Upload.js +55 -20
  177. package/Upload/UploadItem.d.ts +3 -3
  178. package/Upload/UploadItem.js +11 -8
  179. package/Upload/UploadPictureCard.d.ts +5 -0
  180. package/Upload/UploadPictureCard.js +10 -6
  181. package/Upload/Uploader.d.ts +32 -31
  182. package/Upload/Uploader.js +10 -9
  183. package/hooks/useClickAway.d.ts +16 -0
  184. package/hooks/useClickAway.js +16 -0
  185. package/hooks/useComposeRefs.d.ts +15 -0
  186. package/hooks/useComposeRefs.js +15 -0
  187. package/hooks/useDocumentEscapeKeyDown.d.ts +15 -0
  188. package/hooks/useDocumentEscapeKeyDown.js +15 -0
  189. package/hooks/useDocumentEvents.d.ts +16 -0
  190. package/hooks/useDocumentEvents.js +16 -0
  191. package/hooks/useDocumentTabKeyDown.d.ts +15 -0
  192. package/hooks/useDocumentTabKeyDown.js +15 -0
  193. package/hooks/useIsomorphicLayoutEffect.d.ts +16 -0
  194. package/hooks/useIsomorphicLayoutEffect.js +16 -0
  195. package/hooks/useLastCallback.d.ts +15 -0
  196. package/hooks/useLastCallback.js +15 -0
  197. package/hooks/useLastValue.d.ts +18 -0
  198. package/hooks/useLastValue.js +18 -0
  199. package/hooks/usePreviousValue.d.ts +14 -0
  200. package/hooks/usePreviousValue.js +14 -0
  201. package/hooks/useScrollLock.d.ts +6 -4
  202. package/hooks/useScrollLock.js +6 -4
  203. package/hooks/useTopStack.d.ts +17 -0
  204. package/hooks/useTopStack.js +17 -0
  205. package/hooks/useWindowWidth.d.ts +14 -0
  206. package/hooks/useWindowWidth.js +14 -0
  207. package/index.d.ts +6 -4
  208. package/index.js +3 -2
  209. package/llms.txt +200 -0
  210. package/package.json +5 -4
  211. package/Selection/SelectionGroup.d.ts +0 -28
  212. package/Selection/index.d.ts +0 -12
  213. package/Selection/index.js +0 -5
@@ -1,4 +1,4 @@
1
- import { useState, useRef, useCallback, createElement, useMemo } from 'react';
1
+ import { useState, use, useRef, useCallback, createElement, useMemo } from 'react';
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
3
  import { navigationOverflowMenuClasses } from '@mezzanine-ui/core/navigation';
4
4
  import NavigationIconButton from './NavigationIconButton.js';
@@ -6,13 +6,16 @@ import { DotHorizontalIcon } from '@mezzanine-ui/icons';
6
6
  import NavigationOverflowMenuOption from './NavigationOverflowMenuOption.js';
7
7
  import { TransitionGroup } from 'react-transition-group';
8
8
  import { MOTION_EASING, MOTION_DURATION } from '@mezzanine-ui/system/motion';
9
- import { NavigationOptionLevelContext } from './context.js';
9
+ import { NavigationActivatedContext, NavigationOptionLevelContext } from './context.js';
10
10
  import { useDocumentEvents } from '../hooks/useDocumentEvents.js';
11
11
  import Popper from '../Popper/Popper.js';
12
12
  import Translate from '../Transition/Translate.js';
13
+ import Scrollbar from '../Scrollbar/Scrollbar.js';
13
14
 
14
15
  const NavigationOverflowMenu = ({ items, }) => {
15
16
  const [menuOpen, setMenuOpen] = useState(false);
17
+ const { activatedPath, collapsedHiddenKeys } = use(NavigationActivatedContext);
18
+ const isActive = activatedPath.length > 0 && collapsedHiddenKeys.has(activatedPath[0]);
16
19
  const targetRef = useRef(null);
17
20
  const popperRef = useRef(null);
18
21
  const [level1path, setLevel1path] = useState([]);
@@ -75,16 +78,16 @@ const NavigationOverflowMenu = ({ items, }) => {
75
78
  touchend: handleClickAway,
76
79
  };
77
80
  }, [menuOpen]);
78
- return (jsxs(Fragment, { children: [jsx(NavigationIconButton, { ref: targetRef, icon: DotHorizontalIcon, onClick: () => setMenuOpen(!menuOpen) }), jsx(Popper, { anchor: targetRef.current, disablePortal: true, open: menuOpen, options: {
81
+ return (jsxs(Fragment, { children: [jsx(NavigationIconButton, { active: isActive, ref: targetRef, icon: DotHorizontalIcon, onClick: () => setMenuOpen(!menuOpen) }), jsx(Popper, { anchor: targetRef.current, disablePortal: true, open: menuOpen, options: {
79
82
  placement: 'right-end',
80
83
  }, ref: popperRef, children: jsx(TransitionGroup, { component: null, children: menuOpen && (createElement(Translate, { ...translateProps, from: 'bottom', key: "popper-list", in: true },
81
- jsx("li", { className: navigationOverflowMenuClasses.host, children: jsxs("span", { className: navigationOverflowMenuClasses.content, "aria-haspopup": "true", "aria-expanded": menuOpen, children: [jsx("ul", { className: navigationOverflowMenuClasses.subMenu, children: renderedItems }), jsx(NavigationOptionLevelContext.Provider, { value: {
84
+ jsx("li", { className: navigationOverflowMenuClasses.host, children: jsxs("span", { className: navigationOverflowMenuClasses.content, "aria-haspopup": "true", "aria-expanded": menuOpen, children: [jsx(Scrollbar, { className: navigationOverflowMenuClasses.subMenu, children: jsx("ul", { children: renderedItems }) }), jsx(NavigationOptionLevelContext.Provider, { value: {
82
85
  level: 1,
83
86
  path: level1path,
84
- }, children: level2Items.length > 0 && (jsx("ul", { className: navigationOverflowMenuClasses.subMenu, children: renderedItems2 })) }), jsx(NavigationOptionLevelContext.Provider, { value: {
87
+ }, children: level2Items.length > 0 && (jsx(Scrollbar, { className: navigationOverflowMenuClasses.subMenu, children: jsx("ul", { children: renderedItems2 }) })) }), jsx(NavigationOptionLevelContext.Provider, { value: {
85
88
  level: 2,
86
89
  path: level2path,
87
- }, children: level3Items.length > 0 && (jsx("ul", { className: navigationOverflowMenuClasses.subMenu, children: renderedItems3 })) })] }) }))) }) })] }));
90
+ }, children: level3Items.length > 0 && (jsx(Scrollbar, { className: navigationOverflowMenuClasses.subMenu, children: jsx("ul", { children: renderedItems3 }) })) })] }) }))) }) })] }));
88
91
  };
89
92
 
90
93
  export { NavigationOverflowMenu };
@@ -37,7 +37,9 @@ const NavigationUserMenu = forwardRef((props, ref) => {
37
37
  }, onClose: () => {
38
38
  setOpen(false);
39
39
  onClose === null || onClose === void 0 ? void 0 : onClose();
40
- }, children: jsx("button", { className: cx(navigationUserMenuClasses.host, open && navigationUserMenuClasses.open, className), ref: ref, type: "button", children: jsx(Tooltip, { disablePortal: false, options: {
40
+ }, children: jsx("button", { className: cx(navigationUserMenuClasses.host, open && navigationUserMenuClasses.open, className), ref: ref, type: "button", children: jsx(Tooltip, { disablePortal: false, offsetMainAxis: collapsed
41
+ ? 8 + 6 /* 6 is the padding of the item */
42
+ : 8 + 8 /* 8 is the padding of the item and avatar */, options: {
41
43
  placement: collapsed ? 'right' : 'top',
42
44
  }, title: (collapsed || userNameOverflow) && !open ? children : undefined, children: ({ onMouseEnter, onMouseLeave, ref: tooltipRef }) => (jsxs("span", { className: navigationUserMenuClasses.content, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ref: tooltipRef, children: [jsx("span", { className: navigationUserMenuClasses.avatar, children: imgError || !imgSrc ? (jsx(Icon, { icon: UserIcon })) : (jsx("img", { alt: "User avatar", className: navigationUserMenuClasses.avatar, src: imgSrc, onError: () => setImgError(true) })) }), children && (jsx("span", { className: navigationUserMenuClasses.userName, children: jsx("span", { ref: userNameRef, children: children }) })), jsx(Icon, { className: navigationUserMenuClasses.icon, icon: ChevronDownIcon })] })) }) }) }));
43
45
  });
@@ -10,6 +10,7 @@ export declare const NavigationActivatedContext: import("react").Context<{
10
10
  activatedPath: string[];
11
11
  activatedPathKey: string;
12
12
  collapsed: boolean;
13
+ collapsedHiddenKeys: Set<string>;
13
14
  currentPathname: string | null;
14
15
  filterText: string;
15
16
  handleCollapseChange: (newCollapsed: boolean) => void;
@@ -1,10 +1,10 @@
1
- import { FC, Key } from 'react';
1
+ import { FC, Key, PropsWithChildren } from 'react';
2
2
  import { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';
3
3
  import { NotificationSeverity, NotificationType } from '@mezzanine-ui/core/notification-center';
4
4
  import { ButtonProps } from '../Button';
5
- import { Notifier, NotifierConfig, NotifierData } from '../Notifier';
6
- import { SlideProps } from '../Transition';
7
- export interface NotificationConfigProps extends Pick<NotifierConfig, 'duration'>, Pick<SlideProps, 'onEnter' | 'onEntered' | 'onExit' | 'onExited' | 'easing'> {
5
+ import { NotifierConfig, NotifierData } from '../Notifier';
6
+ import { type SlideProps } from '../Transition';
7
+ export interface NotificationConfigProps extends Pick<NotifierConfig, 'duration'>, Pick<SlideProps, 'easing' | 'from' | 'onEnter' | 'onEntered' | 'onExit' | 'onExited'> {
8
8
  /**
9
9
  * Callback function when "View All" button is clicked.
10
10
  * This will be called after closing all notifications.
@@ -112,13 +112,63 @@ export interface NotificationData extends NotifierData, NotificationConfigProps
112
112
  */
113
113
  type?: NotificationType;
114
114
  }
115
- export interface NotificationCenter extends FC<NotificationData>, Notifier<NotificationData, NotificationConfigProps>, Record<NotificationSeverity, (props?: Omit<NotificationData, 'severity'>) => Key> {
115
+ /** Props accepted by NotificationCenter severity shorthand methods such as `NotificationCenter.success`. */
116
+ export type NotificationCenterShorthandProps = Omit<NotificationData, 'severity'>;
117
+ /** Static severity shorthand methods attached to the {@link NotificationCenter} component. */
118
+ export interface NotificationCenterSeverityMethods {
119
+ /** Display an error notification. */
120
+ error: (props?: NotificationCenterShorthandProps) => Key;
121
+ /** Display an informational notification. */
122
+ info: (props?: NotificationCenterShorthandProps) => Key;
123
+ /** Display a success notification. */
124
+ success: (props?: NotificationCenterShorthandProps) => Key;
125
+ /** Display a warning notification. */
126
+ warning: (props?: NotificationCenterShorthandProps) => Key;
116
127
  }
117
128
  /**
118
- * The react component for `mezzanine` notification center.
129
+ * 通知中心元件,支援即時提示(`notification`)與抽屜清單(`drawer`)兩種呈現模式。
119
130
  *
120
- * Use the API from the NotificationCenter instance such as `NotificationCenter.success` and `NotificationCenter.error`
121
- * to display a notification globally.
131
+ * `<NotificationCenter type="notification" />` 宣告式渲染單筆浮動通知;
132
+ * 或使用靜態方法 `NotificationCenter.add()`、`.success()`、`.error()` 等命令式 API
133
+ * 觸發通知,並可透過回傳的 key 呼叫 `remove()` 收回。
134
+ * `type: 'drawer'` 模式下,請搭配 `NotificationCenterDrawer` 以清單方式顯示。
135
+ *
136
+ * @example
137
+ * ```tsx
138
+ * import NotificationCenter from '@mezzanine-ui/react/NotificationCenter';
139
+ *
140
+ * // 宣告式:嵌入畫面中的通知
141
+ * <NotificationCenter
142
+ * reference="notify-1"
143
+ * severity="success"
144
+ * title="儲存成功"
145
+ * type="notification"
146
+ * />
147
+ *
148
+ * // 命令式:觸發浮動通知
149
+ * NotificationCenter.success({ title: '儲存成功', description: '資料已更新。' });
150
+ * NotificationCenter.error({ title: '操作失敗', description: '請稍後再試。' });
151
+ *
152
+ * // 手動控制生命週期
153
+ * const key = NotificationCenter.add({ severity: 'info', title: '處理中…', type: 'notification' });
154
+ * NotificationCenter.remove(key);
155
+ * ```
156
+ *
157
+ * @see {@link NotificationData} 所有可用的通知設定項
158
+ * @see {@link NotificationCenterDrawer} 抽屜清單模式的容器元件
122
159
  */
123
- declare const NotificationCenter: NotificationCenter;
160
+ declare const NotificationCenter: FC<PropsWithChildren<NotificationData>> & {
161
+ add: (notif: NotificationData & {
162
+ key?: Key;
163
+ }) => Key;
164
+ config: (configs: NotificationConfigProps) => void;
165
+ destroy: VoidFunction;
166
+ remove: (key: Key) => void;
167
+ error: (props?: NotificationCenterShorthandProps) => Key;
168
+ info: (props?: NotificationCenterShorthandProps) => Key;
169
+ success: (props?: NotificationCenterShorthandProps) => Key;
170
+ warning: (props?: NotificationCenterShorthandProps) => Key;
171
+ };
172
+ /** Full type of the {@link NotificationCenter} component including all static notification API methods. */
173
+ export type NotificationCenterType = typeof NotificationCenter;
124
174
  export default NotificationCenter;
@@ -1,21 +1,57 @@
1
1
  'use client';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
- import { useState, useRef, useMemo, useEffect, useCallback, Children, isValidElement, Fragment as Fragment$1 } from 'react';
3
+ import { useState, useRef, useMemo, useEffect, useCallback, cloneElement, Children, isValidElement, Fragment as Fragment$1 } from 'react';
4
4
  import { offset, flip } from '@floating-ui/react-dom';
5
5
  import { notificationIcons, notificationClasses } from '@mezzanine-ui/core/notification-center';
6
- import { DotVerticalIcon, CloseIcon } from '@mezzanine-ui/icons';
6
+ import { DotHorizontalIcon, CloseIcon } from '@mezzanine-ui/icons';
7
+ import { MOTION_DURATION, MOTION_EASING } from '@mezzanine-ui/system/motion';
7
8
  import Button from '../Button/Button.js';
8
9
  import ButtonGroup from '../Button/ButtonGroup.js';
10
+ import { reflow } from '../Transition/reflow.js';
11
+ import { useSetNodeTransition } from '../Transition/useSetNodeTransition.js';
9
12
  import Typography from '../Typography/Typography.js';
13
+ import { useComposeRefs } from '../hooks/useComposeRefs.js';
10
14
  import Icon from '../Icon/Icon.js';
11
15
  import Popper from '../Popper/Popper.js';
12
16
  import Dropdown from '../Dropdown/Dropdown.js';
13
17
  import Badge from '../Badge/Badge.js';
14
- import Slide from '../Transition/Slide.js';
15
- import cx from 'clsx';
18
+ import Transition from '../Transition/Transition.js';
16
19
  import { createNotifier } from '../Notifier/createNotifier.js';
20
+ import cx from 'clsx';
17
21
 
18
22
  const DEFAULT_MAX_VISIBLE_NOTIFICATIONS = 3;
23
+ const NOTIFICATION_SLIDE_FADE_DURATION = {
24
+ enter: MOTION_DURATION.slow,
25
+ exit: MOTION_DURATION.moderate,
26
+ };
27
+ const NOTIFICATION_SLIDE_FADE_EASING = {
28
+ enter: MOTION_EASING.standard,
29
+ exit: MOTION_EASING.exit,
30
+ };
31
+ function getNotificationSlideFadeStyle(state, inProp, from) {
32
+ if (state === 'entering' || state === 'entered') {
33
+ return {
34
+ opacity: 1,
35
+ transform: 'translate3d(0, 0, 0)',
36
+ };
37
+ }
38
+ const style = state === 'exiting'
39
+ ? {
40
+ opacity: 0,
41
+ transform: 'translate3d(0, 0, 0)',
42
+ }
43
+ : {
44
+ opacity: 0,
45
+ transform: {
46
+ top: 'translate3d(0, -100%, 0)',
47
+ right: 'translate3d(100%, 0, 0)',
48
+ }[from],
49
+ };
50
+ if (state === 'exited' && !inProp) {
51
+ style.visibility = 'hidden';
52
+ }
53
+ return style;
54
+ }
19
55
  const NotificationCenterContainer = ({ children }) => {
20
56
  const notificationItems = useMemo(() => Children.toArray(children), [children]);
21
57
  // Helper function to extract NotificationCenter component from Fragment or direct element
@@ -42,7 +78,7 @@ const NotificationCenterContainer = ({ children }) => {
42
78
  .map(extractNotificationCenter)
43
79
  .find((notification) => notification !== null);
44
80
  if (firstNotification) {
45
- return (_a = firstNotification.props.maxVisibleNotifications) !== null && _a !== void 0 ? _a : DEFAULT_MAX_VISIBLE_NOTIFICATIONS;
81
+ return ((_a = firstNotification.props.maxVisibleNotifications) !== null && _a !== void 0 ? _a : DEFAULT_MAX_VISIBLE_NOTIFICATIONS);
46
82
  }
47
83
  return DEFAULT_MAX_VISIBLE_NOTIFICATIONS;
48
84
  }, [notificationItems]);
@@ -70,23 +106,36 @@ const NotificationCenterContainer = ({ children }) => {
70
106
  if (!notificationItems.length) {
71
107
  return null;
72
108
  }
73
- return (jsxs(Fragment, { children: [visibleItems, hasOverflow
74
- ? (jsx("div", { className: notificationClasses.viewAllButton, children: jsx(Button, { onClick: handleViewAll, size: "main", variant: "base-secondary", className: notificationClasses.viewAllButtonText, children: viewAllButtonText }) }))
75
- : null] }));
109
+ return (jsxs(Fragment, { children: [visibleItems, hasOverflow ? (jsx("div", { className: notificationClasses.viewAllButton, children: jsx(Button, { onClick: handleViewAll, size: "main", variant: "base-secondary", className: notificationClasses.viewAllButtonText, children: viewAllButtonText }) })) : null] }));
76
110
  };
77
- /**
78
- * The react component for `mezzanine` notification center.
79
- *
80
- * Use the API from the NotificationCenter instance such as `NotificationCenter.success` and `NotificationCenter.error`
81
- * to display a notification globally.
82
- */
83
- const NotificationCenter = ((props) => {
84
- const { type = 'notification', cancelButtonProps = {}, cancelButtonText = 'Cancel', confirmButtonProps = {}, confirmButtonText = 'Confirm', description, duration, onCancel: onCancelProp, onClose: onCloseProp, onConfirm: onConfirmProp, onExited: onExitedProp, reference, severity = 'info', title, timeStamp = new Date().toLocaleTimeString(), timeStampLocale = 'zh-TW', showBadge, onBadgeClick: onBadgeClickProp, options, onBadgeSelect: onBadgeSelectProp, prependTips, appendTips, ...restTransitionProps } = props;
111
+ /** @internal Underlying React element rendered by the NotificationCenter notifier. */
112
+ const NotificationCenterFC = (props) => {
113
+ var _a;
114
+ const { type = 'notification', cancelButtonProps = {}, cancelButtonText = 'Cancel', confirmButtonProps = {}, confirmButtonText = 'Confirm', description, duration, onCancel: onCancelProp, onClose: onCloseProp, onConfirm: onConfirmProp, onExited: onExitedProp, reference, severity = 'info', title, timeStamp = new Date().toLocaleTimeString(), timeStampLocale = 'zh-TW', showBadge, onBadgeClick: onBadgeClickProp, options, onBadgeSelect: onBadgeSelectProp, prependTips, appendTips, from = 'top', ...restTransitionProps } = props;
85
115
  const targetIcon = notificationIcons[severity];
86
116
  const [openDropdown, setOpenDropdown] = useState(false);
87
117
  const [open, setOpen] = useState(true);
88
118
  const [timeStampAnchor, setTimeStampAnchor] = useState(null);
89
119
  const timeStampRef = useRef(null);
120
+ const notificationSlideFadeNodeRef = useRef(null);
121
+ const slideFadeResolvedDuration = NOTIFICATION_SLIDE_FADE_DURATION;
122
+ const slideFadeEasing = (_a = restTransitionProps.easing) !== null && _a !== void 0 ? _a : NOTIFICATION_SLIDE_FADE_EASING;
123
+ const slideFadeDelay = 0;
124
+ const [setSlideTransition, resetSlideTransition] = useSetNodeTransition({
125
+ delay: slideFadeDelay,
126
+ duration: slideFadeResolvedDuration,
127
+ easing: slideFadeEasing,
128
+ properties: ['transform'],
129
+ }, undefined);
130
+ const [setFadeTransition, resetFadeTransition] = useSetNodeTransition({
131
+ delay: slideFadeDelay,
132
+ duration: slideFadeResolvedDuration,
133
+ easing: slideFadeEasing,
134
+ properties: ['opacity'],
135
+ }, undefined);
136
+ const notificationSlideFadeComposedRef = useComposeRefs([
137
+ notificationSlideFadeNodeRef,
138
+ ]);
90
139
  const isToday = useMemo(() => {
91
140
  try {
92
141
  const timestampDate = new Date(timeStamp);
@@ -120,7 +169,9 @@ const NotificationCenter = ((props) => {
120
169
  if (isToday) {
121
170
  const diffInMs = timestampDate.getTime() - now;
122
171
  const diffInSeconds = Math.round(diffInMs / 1000);
123
- const rtf = new Intl.RelativeTimeFormat(timeStampLocale, { numeric: 'always' });
172
+ const rtf = new Intl.RelativeTimeFormat(timeStampLocale, {
173
+ numeric: 'always',
174
+ });
124
175
  const units = [
125
176
  { unit: 'hour', seconds: 3600 },
126
177
  { unit: 'minute', seconds: 60 },
@@ -178,7 +229,7 @@ const NotificationCenter = ((props) => {
178
229
  }, [onBadgeClickProp, setOpenDropdown, options]);
179
230
  const onClose = () => {
180
231
  setOpen(false);
181
- if (onCloseProp) {
232
+ if (onCloseProp && reference !== undefined) {
182
233
  onCloseProp(reference);
183
234
  }
184
235
  };
@@ -198,7 +249,9 @@ const NotificationCenter = ((props) => {
198
249
  if (onExitedProp) {
199
250
  onExitedProp(node);
200
251
  }
201
- NotificationCenter.remove(reference);
252
+ if (reference) {
253
+ NotificationCenter.remove(reference);
254
+ }
202
255
  };
203
256
  const onSelect = useCallback((option) => {
204
257
  if (onBadgeSelectProp) {
@@ -221,14 +274,9 @@ const NotificationCenter = ((props) => {
221
274
  };
222
275
  const showConfirmButton = Boolean(confirmButtonText && onConfirmProp);
223
276
  const showCancelButton = Boolean(cancelButtonText && (onCancelProp || onCloseProp));
224
- const hideButtons = !(type === 'notification' && (showConfirmButton || showCancelButton));
225
- const notificationContent = (jsxs("div", { className: cx(notificationClasses.host, notificationClasses.severity(severity), notificationClasses.type(type)), onMouseEnter: handleNotificationMouseEnter, onMouseLeave: handleNotificationMouseLeave, children: [targetIcon
226
- ? (jsx("div", { className: notificationClasses.iconContainer, children: jsx(Icon, { icon: targetIcon, className: notificationClasses.severityIcon }) }))
227
- : null, jsxs("div", { className: notificationClasses.body, children: [jsxs("div", { className: notificationClasses.bodyContent, children: [jsx("h4", { className: notificationClasses.title, children: title }), jsx(Typography, { className: notificationClasses.content, children: description })] }), !hideButtons && (jsxs(ButtonGroup, { className: notificationClasses.action, children: [showConfirmButton
228
- ? (jsx(Button, { onClick: onConfirm, size: "minor", ...confirmButtonProps, children: confirmButtonText }))
229
- : jsx(Fragment, {}), showCancelButton
230
- ? (jsx(Button, { onClick: onCancel || onClose, size: "minor", variant: "base-secondary", ...cancelButtonProps, children: cancelButtonText }))
231
- : jsx(Fragment, {})] })), type === 'drawer' && (jsxs(Fragment, { children: [isToday && (jsx(Popper, { anchor: timeStampAnchor, open: Boolean(timeStampAnchor), arrow: {
277
+ const hideButtons = !(type === 'notification' &&
278
+ (showConfirmButton || showCancelButton));
279
+ const notificationContent = (jsxs("div", { className: cx(notificationClasses.host, notificationClasses.severity(severity), notificationClasses.type(type)), onMouseEnter: handleNotificationMouseEnter, onMouseLeave: handleNotificationMouseLeave, children: [targetIcon ? (jsx("div", { className: notificationClasses.iconContainer, children: jsx(Icon, { icon: targetIcon, className: notificationClasses.severityIcon, size: 32 }) })) : null, jsxs("div", { className: notificationClasses.body, children: [jsxs("div", { className: notificationClasses.bodyContent, children: [jsx("h4", { className: notificationClasses.title, children: title }), jsx(Typography, { className: notificationClasses.content, children: description })] }), !hideButtons && (jsxs(ButtonGroup, { className: notificationClasses.action, children: [showCancelButton ? (jsx(Button, { onClick: onCancel || onClose, size: "minor", variant: "base-secondary", ...cancelButtonProps, children: cancelButtonText })) : null, showConfirmButton ? (jsx(Button, { onClick: onConfirm, size: "minor", ...confirmButtonProps, children: confirmButtonText })) : null] })), type === 'drawer' && (jsxs(Fragment, { children: [isToday && (jsx(Popper, { anchor: timeStampAnchor, open: Boolean(timeStampAnchor), arrow: {
232
280
  className: notificationClasses.timeStampPopperArrow,
233
281
  enabled: true,
234
282
  padding: 0,
@@ -236,44 +284,92 @@ const NotificationCenter = ((props) => {
236
284
  zIndex: 'var(--mzn-z-index-popover)',
237
285
  }, options: {
238
286
  placement: 'bottom',
239
- middleware: [
240
- offset({ mainAxis: 8 }),
241
- flip(),
242
- ],
243
- }, children: jsx("div", { className: notificationClasses.timeStampPopper, children: jsx(Typography, { className: notificationClasses.timeStampText, children: timeStamp }) }) })), jsx(Typography, { ref: timeStampRef, className: notificationClasses.timeStamp, children: formattedTimeStamp })] }))] }), type === 'drawer'
244
- ? (jsx(Dropdown, { open: openDropdown, onClose: () => setOpenDropdown(false), onVisibilityChange: (open) => setOpenDropdown(open), options: options !== null && options !== void 0 ? options : [], onSelect: onSelect, placement: "bottom-end", zIndex: 'var(--mzn-z-index-popover)', children: jsxs(Button, { variant: "base-ghost", size: "minor", onClick: onClose, children: [showBadge && jsx(Badge, { variant: "dot-error" }), jsx(Icon, { icon: DotVerticalIcon, className: notificationClasses.closeIcon, size: 16, onClick: onBadgeClick })] }) }))
245
- : (jsx(Icon, { icon: CloseIcon, className: notificationClasses.closeIcon, size: 16, onClick: onClose }))] }));
287
+ middleware: [offset({ mainAxis: 8 }), flip()],
288
+ }, children: jsx("div", { className: notificationClasses.timeStampPopper, children: jsx(Typography, { className: notificationClasses.timeStampText, children: timeStamp }) }) })), jsx(Typography, { className: notificationClasses.timeStamp, ref: timeStampRef, variant: "label-secondary", children: formattedTimeStamp })] }))] }), type === 'drawer' ? (jsx(Dropdown, { open: openDropdown, onClose: () => setOpenDropdown(false), onVisibilityChange: (open) => setOpenDropdown(open), options: options !== null && options !== void 0 ? options : [], onSelect: onSelect, placement: "bottom-end", zIndex: 'var(--mzn-z-index-popover)', children: jsxs(Button, { variant: "base-ghost", onClick: onClose, className: notificationClasses.dotIconButton, children: [showBadge && jsx(Badge, { variant: "dot-error" }), jsx(Icon, { icon: DotHorizontalIcon, className: notificationClasses.closeIcon, size: 16, onClick: onBadgeClick })] }) })) : (jsx(Icon, { icon: CloseIcon, className: notificationClasses.closeIcon, size: 16, onClick: onClose }))] }));
246
289
  if (type === 'notification') {
247
- return (jsx(Slide, { in: open, appear: true, onExited: onExited, ...restTransitionProps, children: notificationContent }));
290
+ return (jsx(Transition, { ...restTransitionProps, appear: true, duration: slideFadeResolvedDuration, in: open, nodeRef: notificationSlideFadeNodeRef, onEnter: (node, isAppearing) => {
291
+ var _a;
292
+ setSlideTransition(node, 'enter');
293
+ reflow(node);
294
+ (_a = restTransitionProps.onEnter) === null || _a === void 0 ? void 0 : _a.call(restTransitionProps, node, isAppearing);
295
+ }, onEntered: (node, isAppearing) => {
296
+ var _a;
297
+ resetSlideTransition(node);
298
+ (_a = restTransitionProps.onEntered) === null || _a === void 0 ? void 0 : _a.call(restTransitionProps, node, isAppearing);
299
+ }, onExited: (node) => {
300
+ resetFadeTransition(node);
301
+ onExited(node);
302
+ }, onExit: (node) => {
303
+ var _a;
304
+ setFadeTransition(node, 'exit');
305
+ (_a = restTransitionProps.onExit) === null || _a === void 0 ? void 0 : _a.call(restTransitionProps, node);
306
+ }, children: (state) => cloneElement(notificationContent, {
307
+ ref: notificationSlideFadeComposedRef,
308
+ style: {
309
+ ...getNotificationSlideFadeStyle(state, open, from),
310
+ ...notificationContent.props.style,
311
+ },
312
+ }) }));
248
313
  }
249
- return (jsxs(Fragment, { children: [prependTips && jsx(Typography, { className: notificationClasses.prependTips, children: prependTips }), notificationContent, appendTips && jsx(Typography, { className: notificationClasses.appendTips, children: appendTips })] }));
250
- });
251
- const { add: addNotifier, config, destroy, remove } = createNotifier({
314
+ return (jsxs(Fragment, { children: [prependTips && (jsx(Typography, { className: notificationClasses.prependTips, children: prependTips })), notificationContent, appendTips && (jsx(Typography, { className: notificationClasses.appendTips, children: appendTips }))] }));
315
+ };
316
+ const { add: addNotifier, config, destroy, remove, } = createNotifier({
252
317
  duration: false,
253
318
  render: (notif) => {
254
319
  const { key, ...restNotif } = notif;
255
- return (jsx(NotificationCenter, { ...restNotif, reference: key }, key));
320
+ return jsx(NotificationCenterFC, { ...restNotif, reference: key }, key);
256
321
  },
257
322
  renderContainer: (children) => (jsx(NotificationCenterContainer, { children: children })),
258
323
  setRoot: (root) => {
259
324
  root === null || root === void 0 ? void 0 : root.setAttribute('class', notificationClasses.root);
260
325
  },
261
326
  });
262
- NotificationCenter.add = (notif) => {
263
- if (notif.type === 'drawer') {
264
- return 'NOT_SET';
265
- }
266
- return addNotifier(notif);
267
- };
268
- NotificationCenter.config = config;
269
- NotificationCenter.destroy = destroy;
270
- NotificationCenter.remove = remove;
271
- ['success', 'warning', 'error', 'info'].forEach((severity) => {
272
- NotificationCenter[severity] = (props) => NotificationCenter.add({
273
- ...props,
274
- severity: severity || 'info',
275
- type: 'notification',
276
- });
327
+ /**
328
+ * 通知中心元件,支援即時提示(`notification`)與抽屜清單(`drawer`)兩種呈現模式。
329
+ *
330
+ * 以 `<NotificationCenter type="notification" />` 宣告式渲染單筆浮動通知;
331
+ * 或使用靜態方法 `NotificationCenter.add()`、`.success()`、`.error()` 等命令式 API
332
+ * 觸發通知,並可透過回傳的 key 呼叫 `remove()` 收回。
333
+ * `type: 'drawer'` 模式下,請搭配 `NotificationCenterDrawer` 以清單方式顯示。
334
+ *
335
+ * @example
336
+ * ```tsx
337
+ * import NotificationCenter from '@mezzanine-ui/react/NotificationCenter';
338
+ *
339
+ * // 宣告式:嵌入畫面中的通知
340
+ * <NotificationCenter
341
+ * reference="notify-1"
342
+ * severity="success"
343
+ * title="儲存成功"
344
+ * type="notification"
345
+ * />
346
+ *
347
+ * // 命令式:觸發浮動通知
348
+ * NotificationCenter.success({ title: '儲存成功', description: '資料已更新。' });
349
+ * NotificationCenter.error({ title: '操作失敗', description: '請稍後再試。' });
350
+ *
351
+ * // 手動控制生命週期
352
+ * const key = NotificationCenter.add({ severity: 'info', title: '處理中…', type: 'notification' });
353
+ * NotificationCenter.remove(key);
354
+ * ```
355
+ *
356
+ * @see {@link NotificationData} 所有可用的通知設定項
357
+ * @see {@link NotificationCenterDrawer} 抽屜清單模式的容器元件
358
+ */
359
+ const NotificationCenter = Object.assign(NotificationCenterFC, {
360
+ add: (notif) => {
361
+ if (notif.type === 'drawer') {
362
+ return 'NOT_SET';
363
+ }
364
+ return addNotifier(notif);
365
+ },
366
+ config,
367
+ destroy,
368
+ remove,
369
+ error: (props) => addNotifier({ ...props, severity: 'error', type: 'notification' }),
370
+ info: (props) => addNotifier({ ...props, severity: 'info', type: 'notification' }),
371
+ success: (props) => addNotifier({ ...props, severity: 'success', type: 'notification' }),
372
+ warning: (props) => addNotifier({ ...props, severity: 'warning', type: 'notification' }),
277
373
  });
278
374
 
279
375
  export { NotificationCenter as default };
@@ -1,13 +1,63 @@
1
1
  import { type ComponentProps, type Key, type ReactElement } from 'react';
2
2
  import { DrawerSize } from '@mezzanine-ui/core/drawer';
3
- import { type IconDefinition } from '@mezzanine-ui/icons';
4
3
  import { type DrawerProps } from '../Drawer';
5
4
  import NotificationCenter, { type NotificationData } from './NotificationCenter';
6
5
  type NotificationDataForDrawer = NotificationData & {
7
6
  key: Key;
8
7
  type: 'drawer';
9
8
  };
10
- type NotificationCenterDrawerPropsBase = Pick<DrawerProps, 'controlBarAllRadioLabel' | 'controlBarCustomButtonLabel' | 'controlBarDefaultValue' | 'controlBarOnCustomButtonClick' | 'controlBarOnRadioChange' | 'controlBarReadRadioLabel' | 'controlBarShow' | 'controlBarShowUnreadButton' | 'controlBarUnreadRadioLabel' | 'controlBarValue' | 'onClose' | 'open' | 'renderControlBar'> & {
9
+ type NotificationCenterDrawerPropsBase = Pick<DrawerProps, 'onClose' | 'open'> & {
10
+ /**
11
+ * Label for the "all" filter option in the filter bar.
12
+ */
13
+ filterBarAllRadioLabel?: DrawerProps['filterAreaAllRadioLabel'];
14
+ /**
15
+ * Label for the custom action button in the filter bar.
16
+ */
17
+ filterBarCustomButtonLabel?: DrawerProps['filterAreaCustomButtonLabel'];
18
+ /**
19
+ * Default selected filter value in the filter bar.
20
+ */
21
+ filterBarDefaultValue?: DrawerProps['filterAreaDefaultValue'];
22
+ /**
23
+ * Callback fired when the custom action button is clicked.
24
+ */
25
+ filterBarOnCustomButtonClick?: DrawerProps['filterAreaOnCustomButtonClick'];
26
+ /**
27
+ * Callback fired when the filter option changes.
28
+ */
29
+ filterBarOnRadioChange?: DrawerProps['filterAreaOnRadioChange'];
30
+ /**
31
+ * Label for the "read" filter option in the filter bar.
32
+ */
33
+ filterBarReadRadioLabel?: DrawerProps['filterAreaReadRadioLabel'];
34
+ /**
35
+ * Whether to show the filter bar.
36
+ */
37
+ filterBarShow?: DrawerProps['filterAreaShow'];
38
+ /**
39
+ * Whether to show the "unread only" shortcut button.
40
+ */
41
+ filterBarShowUnreadButton?: DrawerProps['filterAreaShowUnreadButton'];
42
+ /**
43
+ * Label for the "unread" filter option in the filter bar.
44
+ */
45
+ filterBarUnreadRadioLabel?: DrawerProps['filterAreaUnreadRadioLabel'];
46
+ /**
47
+ * Controlled selected filter value in the filter bar.
48
+ */
49
+ filterBarValue?: DrawerProps['filterAreaValue'];
50
+ /**
51
+ * Options for the filter bar dropdown.
52
+ * When non-empty, the right-side filter area button is replaced by a Dropdown
53
+ * triggered by a `DotHorizontalIcon` icon button.
54
+ */
55
+ filterBarOptions?: DrawerProps['filterAreaOptions'];
56
+ /**
57
+ * Callback fired when a filter bar dropdown option is selected.
58
+ * Only used when `filterBarOptions` is non-empty.
59
+ */
60
+ filterBarOnSelect?: DrawerProps['filterAreaOnSelect'];
11
61
  /**
12
62
  * The size of the drawer.
13
63
  * @default 'narrow'
@@ -18,14 +68,14 @@ type NotificationCenterDrawerPropsBase = Pick<DrawerProps, 'controlBarAllRadioLa
18
68
  * @default '更早'
19
69
  */
20
70
  earlierLabel?: string;
21
- /**
22
- * The icon of the empty notification.
23
- */
24
- emptyNotificationIcon?: IconDefinition;
25
71
  /**
26
72
  * The title of the empty notification.
27
73
  */
28
74
  emptyNotificationTitle?: string;
75
+ /**
76
+ * The description of the empty notification.
77
+ */
78
+ emptyNotificationDescription?: string;
29
79
  /**
30
80
  * The label for the "past 7 days" time group.
31
81
  * @default '過去七天'
@@ -1,12 +1,10 @@
1
1
  'use client';
2
- import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { jsx } from 'react/jsx-runtime';
3
3
  import { useMemo } from 'react';
4
4
  import { notificationClasses } from '@mezzanine-ui/core/notification-center';
5
- import { NotificationIcon } from '@mezzanine-ui/icons';
6
- import Typography from '../Typography/Typography.js';
7
5
  import NotificationCenter from './NotificationCenter.js';
8
6
  import Drawer from '../Drawer/Drawer.js';
9
- import Icon from '../Icon/Icon.js';
7
+ import Empty from '../Empty/Empty.js';
10
8
 
11
9
  const isValidTime = (timestamp) => {
12
10
  if (!timestamp)
@@ -57,7 +55,7 @@ const getTimeGroup = (timestamp, now) => {
57
55
  return 'earlier';
58
56
  };
59
57
  const NotificationCenterDrawer = (props) => {
60
- const { children, controlBarAllRadioLabel, controlBarCustomButtonLabel, controlBarDefaultValue, controlBarOnCustomButtonClick, controlBarOnRadioChange, controlBarReadRadioLabel, controlBarShow, controlBarShowUnreadButton, controlBarUnreadRadioLabel, controlBarValue, drawerSize = 'narrow', earlierLabel, emptyNotificationIcon = NotificationIcon, emptyNotificationTitle = '目前沒有新的通知', notificationList, onClose, open, past7DaysLabel, renderControlBar, title, todayLabel, yesterdayLabel, ...restDrawerProps } = props;
58
+ const { children, filterBarAllRadioLabel, filterBarCustomButtonLabel, filterBarDefaultValue, filterBarOnCustomButtonClick, filterBarOnRadioChange, filterBarOnSelect, filterBarReadRadioLabel, filterBarShow, filterBarShowUnreadButton, filterBarUnreadRadioLabel, filterBarValue, filterBarOptions, drawerSize = 'narrow', earlierLabel, emptyNotificationTitle = '目前沒有新的通知', emptyNotificationDescription = '當有新的系統通知時,將會顯示在這裡。', notificationList, onClose, open, past7DaysLabel, title, todayLabel, yesterdayLabel, ...restDrawerProps } = props;
61
59
  const isEmpty = useMemo(() => {
62
60
  if (notificationList) {
63
61
  return notificationList.length === 0;
@@ -69,7 +67,7 @@ const NotificationCenterDrawer = (props) => {
69
67
  }, [notificationList, children]);
70
68
  const renderNotifications = useMemo(() => {
71
69
  const renderEmptyNotifications = () => {
72
- return (jsxs("div", { className: notificationClasses.emptyNotifications, children: [jsx(Icon, { icon: emptyNotificationIcon, size: 28 }), jsx(Typography, { children: emptyNotificationTitle })] }));
70
+ return (jsx("div", { className: notificationClasses.emptyNotifications, children: jsx(Empty, { type: "notification", size: "main", title: emptyNotificationTitle, description: emptyNotificationDescription }) }));
73
71
  };
74
72
  if (isEmpty) {
75
73
  return renderEmptyNotifications();
@@ -115,14 +113,14 @@ const NotificationCenterDrawer = (props) => {
115
113
  isEmpty,
116
114
  notificationList,
117
115
  children,
118
- emptyNotificationIcon,
119
116
  emptyNotificationTitle,
117
+ emptyNotificationDescription,
120
118
  earlierLabel,
121
119
  past7DaysLabel,
122
120
  todayLabel,
123
121
  yesterdayLabel,
124
122
  ]);
125
- return (jsx(Drawer, { className: notificationClasses.drawer, controlBarAllRadioLabel: controlBarAllRadioLabel, controlBarCustomButtonLabel: controlBarCustomButtonLabel, controlBarDefaultValue: controlBarDefaultValue, controlBarIsEmpty: isEmpty, controlBarOnCustomButtonClick: controlBarOnCustomButtonClick, controlBarOnRadioChange: controlBarOnRadioChange, controlBarReadRadioLabel: controlBarReadRadioLabel, controlBarShow: controlBarShow, controlBarShowUnreadButton: controlBarShowUnreadButton, controlBarUnreadRadioLabel: controlBarUnreadRadioLabel, controlBarValue: controlBarValue, headerTitle: title, isHeaderDisplay: Boolean(title), onClose: onClose, open: open, renderControlBar: renderControlBar, size: drawerSize, ...restDrawerProps, children: renderNotifications }));
123
+ return (jsx(Drawer, { className: notificationClasses.drawer, filterAreaAllRadioLabel: filterBarAllRadioLabel, filterAreaCustomButtonLabel: filterBarCustomButtonLabel, filterAreaDefaultValue: filterBarDefaultValue, filterAreaIsEmpty: isEmpty, filterAreaOnCustomButtonClick: filterBarOnCustomButtonClick, filterAreaOnRadioChange: filterBarOnRadioChange, filterAreaOnSelect: filterBarOnSelect, filterAreaReadRadioLabel: filterBarReadRadioLabel, filterAreaShow: filterBarShow, filterAreaShowUnreadButton: filterBarShowUnreadButton, filterAreaUnreadRadioLabel: filterBarUnreadRadioLabel, filterAreaValue: filterBarValue, filterAreaOptions: filterBarOptions, headerTitle: title, isHeaderDisplay: Boolean(title), onClose: onClose, open: open, size: drawerSize, ...restDrawerProps, children: jsx("div", { className: notificationClasses.notificationsContainer, children: renderNotifications }) }));
126
124
  };
127
125
 
128
126
  export { NotificationCenterDrawer as default };
@@ -1,5 +1,5 @@
1
1
  export type { NotificationSeverity } from '@mezzanine-ui/core/notification-center';
2
2
  export { default } from './NotificationCenter';
3
- export type { NotificationConfigProps, NotificationData, } from './NotificationCenter';
3
+ export type { NotificationCenterShorthandProps, NotificationCenterSeverityMethods, NotificationCenterType, NotificationConfigProps, NotificationData, } from './NotificationCenter';
4
4
  export { default as NotificationCenterDrawer } from './NotificationCenterDrawer';
5
5
  export type { NotificationCenterDrawerProps } from './NotificationCenterDrawer';