@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,8 +1,8 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { forwardRef, useState, useEffect } from 'react';
3
+ import { forwardRef, useState, useEffect, useRef } from 'react';
4
4
  import { overflowTooltipClasses } from '@mezzanine-ui/core/overflow-tooltip';
5
- import { getCSSVariableValue } from '../utils/get-css-variable-value.js';
5
+ import { getNumericCSSVariablePixelValue } from '../utils/get-css-variable-value.js';
6
6
  import { offset, flip, shift } from '@floating-ui/react-dom';
7
7
  import { spacingPrefix } from '@mezzanine-ui/system/spacing';
8
8
  import { MOTION_EASING, MOTION_DURATION } from '@mezzanine-ui/system/motion';
@@ -16,8 +16,9 @@ import cx from 'clsx';
16
16
  */
17
17
  const OverflowTooltip = forwardRef(function OverflowTooltip(props, ref) {
18
18
  const { anchor, className, onTagDismiss, open, placement = 'top-start', readOnly, tags, tagSize, } = props;
19
- const offsetValue = Number(getCSSVariableValue(`--${spacingPrefix}-gap-base`).replace('rem', '')) * 16;
20
- const arrowHeight = Number(getCSSVariableValue(`--${spacingPrefix}-size-element-tight`).replace('rem', '')) * 16;
19
+ const offsetValue = getNumericCSSVariablePixelValue(`--${spacingPrefix}-gap-base`);
20
+ const arrowHeight = getNumericCSSVariablePixelValue(`--${spacingPrefix}-size-element-tight`);
21
+ const arrowPadding = getNumericCSSVariablePixelValue(`--${spacingPrefix}-padding-horizontal-comfort`);
21
22
  const middleware = [offset({ mainAxis: offsetValue + arrowHeight })];
22
23
  const flipMiddleware = flip({
23
24
  crossAxis: 'alignment',
@@ -36,7 +37,47 @@ const OverflowTooltip = forwardRef(function OverflowTooltip(props, ref) {
36
37
  setPopperOpen(true);
37
38
  }
38
39
  }, [open]);
39
- return (jsx(Popper, { ref: ref, anchor: anchor, open: popperOpen, arrow: { enabled: true, className: overflowTooltipClasses.arrow }, className: cx(overflowTooltipClasses.host, className), options: { placement, middleware }, children: jsx(Fade, { in: open, duration: {
40
+ const contentRef = useRef(null);
41
+ useEffect(() => {
42
+ if (!popperOpen)
43
+ return;
44
+ const rafId = requestAnimationFrame(() => {
45
+ const content = contentRef.current;
46
+ if (!content)
47
+ return;
48
+ content.style.width = '';
49
+ const children = Array.from(content.children);
50
+ if (!children.length)
51
+ return;
52
+ const rows = new Map();
53
+ children.forEach((child) => {
54
+ const top = Math.round(child.getBoundingClientRect().top);
55
+ if (!rows.has(top))
56
+ rows.set(top, []);
57
+ const arr = rows.get(top);
58
+ if (arr) {
59
+ arr.push(child);
60
+ }
61
+ });
62
+ const style = getComputedStyle(content);
63
+ const paddingLeft = parseFloat(style.paddingLeft);
64
+ const paddingRight = parseFloat(style.paddingRight);
65
+ const contentLeft = content.getBoundingClientRect().left;
66
+ let maxRowWidth = 0;
67
+ rows.forEach((rowItems) => {
68
+ const lastItem = rowItems[rowItems.length - 1];
69
+ const rowWidth = lastItem.getBoundingClientRect().right - contentLeft - paddingLeft;
70
+ maxRowWidth = Math.max(maxRowWidth, rowWidth);
71
+ });
72
+ content.style.width = `${maxRowWidth + paddingLeft + paddingRight}px`;
73
+ });
74
+ return () => cancelAnimationFrame(rafId);
75
+ }, [tags, popperOpen, tagSize, readOnly]);
76
+ return (jsx(Popper, { ref: ref, anchor: anchor, open: popperOpen, arrow: {
77
+ enabled: true,
78
+ className: overflowTooltipClasses.arrow,
79
+ padding: arrowPadding,
80
+ }, className: cx(overflowTooltipClasses.host, className), options: { placement, middleware }, children: jsx(Fade, { ref: contentRef, in: open, duration: {
40
81
  enter: MOTION_DURATION.fast,
41
82
  exit: MOTION_DURATION.fast,
42
83
  }, easing: {
@@ -67,7 +67,7 @@ type PageFooterOverflowProps = PageFooterBaseProps & {
67
67
  type: 'overflow';
68
68
  /**
69
69
  * Overflow type: Icon for the icon-only button.
70
- * @default DotVerticalIcon
70
+ * @default DotHorizontalIcon
71
71
  */
72
72
  supportingActionIcon?: ButtonProps['icon'];
73
73
  /**
@@ -4,35 +4,27 @@ import { pageFooterClasses } from '@mezzanine-ui/core/page-footer';
4
4
  import Button from '../Button/Button.js';
5
5
  import ButtonGroup from '../Button/ButtonGroup.js';
6
6
  import Typography from '../Typography/Typography.js';
7
- import { DotVerticalIcon } from '@mezzanine-ui/icons';
7
+ import { DotHorizontalIcon } from '@mezzanine-ui/icons';
8
8
  import Dropdown from '../Dropdown/Dropdown.js';
9
9
  import cx from 'clsx';
10
10
 
11
11
  const PageFooter = forwardRef(function PageFooter(props, ref) {
12
12
  var _a;
13
- const { actions, annotationClassName, className, type = 'standard', warningMessage, ...rest } = props;
14
- // Filter out onAnnotationClick from rest props to avoid React warnings
15
- if ('onAnnotationClick' in rest) {
16
- delete rest.onAnnotationClick;
17
- }
13
+ const { actions, annotationClassName, annotation, className, dropdownProps, supportingActionIcon, supportingActionName, supportingActionOnClick, supportingActionType, supportingActionVariant = 'base-ghost', type = 'standard', warningMessage, ...rest } = props;
18
14
  const { children: primaryButtonText, ...restPrimaryButtonProps } = (_a = actions === null || actions === void 0 ? void 0 : actions.primaryButton) !== null && _a !== void 0 ? _a : {};
19
15
  // Render annotation based on type
20
16
  const renderAnnotation = () => {
21
17
  switch (type) {
22
- case 'standard': {
23
- const { supportingActionName, supportingActionType, supportingActionOnClick, supportingActionVariant = 'base-ghost', } = props;
18
+ case 'standard':
24
19
  return (jsx(Button, { size: "main", type: supportingActionType, onClick: supportingActionOnClick, variant: supportingActionVariant, children: supportingActionName }));
25
- }
26
- case 'overflow': {
27
- const { supportingActionIcon, dropdownProps } = props;
28
- return (jsx(Dropdown, { ...dropdownProps, options: dropdownProps.options || [], placement: dropdownProps.placement || 'top', children: jsx(Button, { type: "button", iconType: "icon-only", icon: supportingActionIcon || DotVerticalIcon, size: "main", variant: "base-ghost" }) }));
29
- }
30
- case 'information': {
31
- const { annotation } = props;
20
+ case 'overflow':
21
+ if (!dropdownProps)
22
+ return null;
23
+ return (jsx(Dropdown, { ...dropdownProps, options: dropdownProps.options || [], placement: dropdownProps.placement || 'top', children: jsx(Button, { type: "button", iconType: "icon-only", icon: supportingActionIcon || DotHorizontalIcon, size: "main", variant: "base-ghost" }) }));
24
+ case 'information':
32
25
  if (!annotation)
33
26
  return null;
34
27
  return (jsx(Typography, { color: "text-neutral", variant: "caption", children: annotation }));
35
- }
36
28
  default:
37
29
  return null;
38
30
  }
@@ -93,7 +93,44 @@ export interface PaginationProps extends Omit<DetailedHTMLProps<HTMLAttributes<H
93
93
  total?: number;
94
94
  }
95
95
  /**
96
- * The react component for `mezzanine` pagination.
96
+ * 分頁導覽元件,提供頁碼切換、頁碼跳轉輸入框以及每頁筆數選擇器。
97
+ *
98
+ * 傳入 `total` 與 `pageSize` 自動計算總頁數並渲染頁碼列表;`boundaryCount` 控制首尾
99
+ * 始終顯示的頁數,`siblingCount` 控制當前頁兩側的頁數。啟用 `showJumper` 可直接輸入頁碼跳轉,
100
+ * 啟用 `showPageSizeOptions` 可讓使用者選擇每頁顯示筆數。
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * import Pagination from '@mezzanine-ui/react/Pagination';
105
+ *
106
+ * // 基本用法
107
+ * <Pagination total={100} current={page} onChange={setPage} />
108
+ *
109
+ * // 顯示結果摘要與每頁筆數選擇器
110
+ * <Pagination
111
+ * total={200}
112
+ * current={page}
113
+ * pageSize={pageSize}
114
+ * onChange={setPage}
115
+ * onChangePageSize={setPageSize}
116
+ * showPageSizeOptions
117
+ * pageSizeOptions={[10, 20, 50]}
118
+ * renderResultSummary={(from, to, total) => `顯示 ${from}–${to} 筆,共 ${total} 筆`}
119
+ * />
120
+ *
121
+ * // 顯示頁碼跳轉輸入框
122
+ * <Pagination
123
+ * total={500}
124
+ * current={page}
125
+ * onChange={setPage}
126
+ * showJumper
127
+ * hintText="前往"
128
+ * buttonText="GO"
129
+ * />
130
+ * ```
131
+ *
132
+ * @see {@link Table} 搭配 Table 元件的 `pagination` prop 使用
133
+ * @see {@link usePagination} 獨立使用分頁邏輯的 hook
97
134
  */
98
135
  declare const Pagination: import("react").ForwardRefExoticComponent<Omit<PaginationProps, "ref"> & import("react").RefAttributes<HTMLElement>>;
99
136
  export default Pagination;
@@ -9,7 +9,44 @@ import Typography from '../Typography/Typography.js';
9
9
  import cx from 'clsx';
10
10
 
11
11
  /**
12
- * The react component for `mezzanine` pagination.
12
+ * 分頁導覽元件,提供頁碼切換、頁碼跳轉輸入框以及每頁筆數選擇器。
13
+ *
14
+ * 傳入 `total` 與 `pageSize` 自動計算總頁數並渲染頁碼列表;`boundaryCount` 控制首尾
15
+ * 始終顯示的頁數,`siblingCount` 控制當前頁兩側的頁數。啟用 `showJumper` 可直接輸入頁碼跳轉,
16
+ * 啟用 `showPageSizeOptions` 可讓使用者選擇每頁顯示筆數。
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import Pagination from '@mezzanine-ui/react/Pagination';
21
+ *
22
+ * // 基本用法
23
+ * <Pagination total={100} current={page} onChange={setPage} />
24
+ *
25
+ * // 顯示結果摘要與每頁筆數選擇器
26
+ * <Pagination
27
+ * total={200}
28
+ * current={page}
29
+ * pageSize={pageSize}
30
+ * onChange={setPage}
31
+ * onChangePageSize={setPageSize}
32
+ * showPageSizeOptions
33
+ * pageSizeOptions={[10, 20, 50]}
34
+ * renderResultSummary={(from, to, total) => `顯示 ${from}–${to} 筆,共 ${total} 筆`}
35
+ * />
36
+ *
37
+ * // 顯示頁碼跳轉輸入框
38
+ * <Pagination
39
+ * total={500}
40
+ * current={page}
41
+ * onChange={setPage}
42
+ * showJumper
43
+ * hintText="前往"
44
+ * buttonText="GO"
45
+ * />
46
+ * ```
47
+ *
48
+ * @see {@link Table} 搭配 Table 元件的 `pagination` prop 使用
49
+ * @see {@link usePagination} 獨立使用分頁邏輯的 hook
13
50
  */
14
51
  const Pagination = forwardRef((props, ref) => {
15
52
  const { boundaryCount = 1, buttonText, className, current = 1, disabled, hintText, inputPlaceholder, itemRender = (item) => jsx(PaginationItem, { ...item }), onChange, onChangePageSize, pageSize = 10, pageSizeLabel, pageSizeOptions, renderPageSizeOptionName, renderResultSummary, showJumper = false, showPageSizeOptions = false, siblingCount = 1, total = 0, ...rest } = props;
@@ -25,7 +25,7 @@ const PaginationPageSize = forwardRef((props, ref) => {
25
25
  onChange === null || onChange === void 0 ? void 0 : onChange(Number(option.id));
26
26
  setOpen(false);
27
27
  };
28
- return (jsxs("div", { ...rest, ref: ref, className: cx(paginationPageSizeClasses.host, className), children: [label ? (jsx(Typography, { component: "div", ellipsis: true, variant: "label-primary", children: label })) : null, jsx(Dropdown, { disabled: disabled, onSelect: dropDownOnSelect, onVisibilityChange: setOpen, open: open, options: selectOptions, sameWidth: true, children: jsx(SelectTrigger, { className: paginationPageSizeClasses.select, disabled: disabled, size: "sub", value: currentValue }) })] }));
28
+ return (jsxs("div", { ...rest, ref: ref, className: cx(paginationPageSizeClasses.host, className), children: [label ? (jsx(Typography, { component: "div", ellipsis: true, variant: "label-primary", children: label })) : null, jsx(Dropdown, { disabled: disabled, minWidth: 0, onSelect: dropDownOnSelect, onVisibilityChange: setOpen, open: open, options: selectOptions, sameWidth: true, value: currentValue === null || currentValue === void 0 ? void 0 : currentValue.id, children: jsx(SelectTrigger, { className: paginationPageSizeClasses.select, disabled: disabled, size: "sub", value: currentValue }) })] }));
29
29
  });
30
30
 
31
31
  export { PaginationPageSize as default };
@@ -13,6 +13,26 @@ export interface UsePaginationParams {
13
13
  total?: number;
14
14
  }
15
15
  export declare const range: (start: number, end: number) => number[];
16
+ /**
17
+ * 計算分頁項目清單的 Hook。
18
+ *
19
+ * 根據 `total`、`pageSize`、`current`、`boundaryCount` 與 `siblingCount` 等參數,
20
+ * 計算出包含頁碼按鈕、省略號、上一頁、下一頁的 `PaginationItemProps` 陣列。
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * import { usePagination } from '@mezzanine-ui/react';
25
+ *
26
+ * const { items } = usePagination({
27
+ * total: 100,
28
+ * pageSize: 10,
29
+ * current: 1,
30
+ * onChange: (page) => setCurrentPage(page),
31
+ * });
32
+ * ```
33
+ *
34
+ * @see {@link Pagination} 搭配的元件
35
+ */
16
36
  export declare function usePagination(props?: UsePaginationParams): {
17
37
  items: PaginationItemProps[];
18
38
  };
@@ -4,6 +4,26 @@ const range = (start, end) => {
4
4
  const length = end - start + 1;
5
5
  return Array.from({ length }, (_, i) => start + i);
6
6
  };
7
+ /**
8
+ * 計算分頁項目清單的 Hook。
9
+ *
10
+ * 根據 `total`、`pageSize`、`current`、`boundaryCount` 與 `siblingCount` 等參數,
11
+ * 計算出包含頁碼按鈕、省略號、上一頁、下一頁的 `PaginationItemProps` 陣列。
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * import { usePagination } from '@mezzanine-ui/react';
16
+ *
17
+ * const { items } = usePagination({
18
+ * total: 100,
19
+ * pageSize: 10,
20
+ * current: 1,
21
+ * onChange: (page) => setCurrentPage(page),
22
+ * });
23
+ * ```
24
+ *
25
+ * @see {@link Pagination} 搭配的元件
26
+ */
7
27
  function usePagination(props = {}) {
8
28
  const { boundaryCount = 1, current = 1, disabled = false, onChange: handleChange, pageSize = 10, siblingCount = 1, total = 0, } = props;
9
29
  const totalPages = total ? Math.ceil(total / pageSize) : 1;
@@ -45,7 +45,30 @@ export interface ProgressProps extends Omit<NativeElementPropsWithoutKeyAndRef<'
45
45
  type?: ProgressType;
46
46
  }
47
47
  /**
48
- * The react component for `mezzanine` progress.
48
+ * 進度條元件,支援百分比文字與狀態圖示兩種顯示類型。
49
+ *
50
+ * `percent` 介於 0~100,未達 100 時狀態自動為 `enabled`,達到 100 時自動切換為 `success`。
51
+ * 可強制指定 `status` 為 `error` 以顯示錯誤圖示;使用 `tick` prop 可在進度條上標記特定位置。
52
+ * 支援 `icons` prop 自訂 success 與 error 狀態的圖示。
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * import Progress from '@mezzanine-ui/react/Progress';
57
+ *
58
+ * // 基本進度條
59
+ * <Progress percent={60} />
60
+ *
61
+ * // 顯示百分比文字
62
+ * <Progress percent={75} type="percent" />
63
+ *
64
+ * // 錯誤狀態
65
+ * <Progress percent={40} status="error" type="icon" />
66
+ *
67
+ * // 帶有 tick 標記點
68
+ * <Progress percent={60} tick={80} />
69
+ * ```
70
+ *
71
+ * @see {@link Spin} 載入旋轉元件
49
72
  */
50
73
  declare const Progress: import("react").ForwardRefExoticComponent<ProgressProps & import("react").RefAttributes<HTMLDivElement>>;
51
74
  export default Progress;
@@ -8,7 +8,30 @@ import Icon from '../Icon/Icon.js';
8
8
  import cx from 'clsx';
9
9
 
10
10
  /**
11
- * The react component for `mezzanine` progress.
11
+ * 進度條元件,支援百分比文字與狀態圖示兩種顯示類型。
12
+ *
13
+ * `percent` 介於 0~100,未達 100 時狀態自動為 `enabled`,達到 100 時自動切換為 `success`。
14
+ * 可強制指定 `status` 為 `error` 以顯示錯誤圖示;使用 `tick` prop 可在進度條上標記特定位置。
15
+ * 支援 `icons` prop 自訂 success 與 error 狀態的圖示。
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * import Progress from '@mezzanine-ui/react/Progress';
20
+ *
21
+ * // 基本進度條
22
+ * <Progress percent={60} />
23
+ *
24
+ * // 顯示百分比文字
25
+ * <Progress percent={75} type="percent" />
26
+ *
27
+ * // 錯誤狀態
28
+ * <Progress percent={40} status="error" type="icon" />
29
+ *
30
+ * // 帶有 tick 標記點
31
+ * <Progress percent={60} tick={80} />
32
+ * ```
33
+ *
34
+ * @see {@link Spin} 載入旋轉元件
12
35
  */
13
36
  const Progress = forwardRef(function Progress(props, ref) {
14
37
  const { className, icons, percent = 0, percentProps, status = percent < 100
package/README.md CHANGED
@@ -1 +1,83 @@
1
1
  # @mezzanine-ui/react
2
+
3
+ React component library for Mezzanine UI. Provides a comprehensive set of accessible, themeable UI components built on top of `@mezzanine-ui/core`, `@mezzanine-ui/icons`, and `@mezzanine-ui/system`.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mezzanine-ui/react @mezzanine-ui/core @mezzanine-ui/icons @mezzanine-ui/system
9
+ ```
10
+
11
+ ## Peer Dependencies
12
+
13
+ | Package | Version |
14
+ | ----------- | ------- |
15
+ | `react` | `>= 18` |
16
+ | `react-dom` | `>= 18` |
17
+ | `lodash` | `>= 4` |
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. Setup Styles
22
+
23
+ Create a `main.scss` and import it at your app entry point:
24
+
25
+ ```scss
26
+ @use '@mezzanine-ui/system' as mzn-system;
27
+ @use '@mezzanine-ui/core' as mzn-core;
28
+
29
+ :root {
30
+ @include mzn-system.common-variables('default');
31
+ @include mzn-system.colors();
32
+ @include mzn-system.palette-variables(light);
33
+ }
34
+
35
+ /* Optional: dark mode */
36
+ [data-theme='dark'] {
37
+ @include mzn-system.palette-variables(dark);
38
+ }
39
+
40
+ /* Optional: compact density */
41
+ [data-density='compact'] {
42
+ @include mzn-system.common-variables(compact);
43
+ }
44
+
45
+ @include mzn-core.styles();
46
+ ```
47
+
48
+ > **Note:** The `~` prefix (e.g. `~@mezzanine-ui/system`) was required by older webpack 4 + sass-loader setups. Modern tooling (Next.js 13+, Vite) resolves node_modules without it.
49
+
50
+ ```tsx
51
+ // app entry (e.g. main.tsx / _app.tsx)
52
+ import './main.scss';
53
+ ```
54
+
55
+ ### 2. Use Components
56
+
57
+ ```tsx
58
+ import Button from '@mezzanine-ui/react/Button';
59
+
60
+ function App() {
61
+ return <Button variant="base-primary">Click me</Button>;
62
+ }
63
+ ```
64
+
65
+ ## Component Catalog
66
+
67
+ See [COMPONENTS.md](./COMPONENTS.md) for the full list of available components, their import names, and descriptions.
68
+
69
+ ## AI Tooling Note
70
+
71
+ All published `.d.ts` files include JSDoc comments with `@example` blocks referencing `@mezzanine-ui/react` import paths. AI tools (e.g. GitHub Copilot, Claude) can use these to generate accurate component usage without additional documentation lookups.
72
+
73
+ ## Related Packages
74
+
75
+ | Package | Description |
76
+ | ---------------------- | --------------------------------------------- |
77
+ | `@mezzanine-ui/core` | CSS styles and TypeScript types per component |
78
+ | `@mezzanine-ui/icons` | SVG icon definitions |
79
+ | `@mezzanine-ui/system` | Design tokens and CSS custom properties |
80
+
81
+ ## License
82
+
83
+ MIT
package/Radio/Radio.d.ts CHANGED
@@ -37,7 +37,9 @@ export interface RadioBaseProps extends Omit<InputCheckProps, 'control' | 'htmlF
37
37
  value?: string;
38
38
  }
39
39
  export interface RadioNormalProps extends RadioBaseProps {
40
+ /** 此模式下不適用,僅限 segment 類型。 */
40
41
  icon?: never;
42
+ /** 顯示在 radio 標籤下方的輔助說明文字。 */
41
43
  hint?: string;
42
44
  /**
43
45
  * The type of radio.
@@ -58,17 +60,49 @@ export interface RadioSegmentProps extends RadioBaseProps {
58
60
  * The icon in radio prefix.
59
61
  */
60
62
  icon?: IconDefinition;
63
+ /** 此模式下不適用,僅限 radio 類型。 */
61
64
  hint?: never;
62
65
  /**
63
66
  * The type of radio.
64
67
  * @default 'radio'
65
68
  */
66
69
  type: 'segment';
70
+ /** 此模式下不適用,僅限 radio 類型。 */
67
71
  withInputConfig?: never;
68
72
  }
69
73
  export type RadioProps = RadioNormalProps | RadioSegmentProps;
70
74
  /**
71
- * The react component for `mezzanine` radio.
75
+ * 單選按鈕元件,支援標準(radio)與區段(segment)兩種類型。
76
+ *
77
+ * 在 `RadioGroup` 內使用時,會自動繼承群組的 `name`、`size` 與 `type`;
78
+ * 也可獨立使用,透過 `checked`/`defaultChecked` 進行受控或非受控操作。
79
+ * `segment` 類型可搭配 `icon` 屬性顯示圖示,適合用於分頁切換情境。
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * import Radio from '@mezzanine-ui/react/Radio';
84
+ *
85
+ * // 基本用法(非受控)
86
+ * <Radio value="male" inputProps={{ name: 'gender' }}>男性</Radio>
87
+ *
88
+ * // 受控用法
89
+ * const [value, setValue] = useState('a');
90
+ * <Radio
91
+ * checked={value === 'a'}
92
+ * value="a"
93
+ * inputProps={{ name: 'option' }}
94
+ * onChange={() => setValue('a')}
95
+ * >
96
+ * 選項 A
97
+ * </Radio>
98
+ *
99
+ * // Segment 類型搭配圖示
100
+ * import { ListIcon } from '@mezzanine-ui/icons';
101
+ * <Radio type="segment" icon={ListIcon} value="list">列表</Radio>
102
+ * ```
103
+ *
104
+ * @see {@link RadioGroup} 管理多個單選按鈕的群組元件
105
+ * @see {@link useRadioControlValue} 單選按鈕受控值的自訂 Hook
72
106
  */
73
107
  declare const Radio: import("react").ForwardRefExoticComponent<RadioProps & import("react").RefAttributes<HTMLDivElement>>;
74
108
  export default Radio;
package/Radio/Radio.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { forwardRef, useContext, useState } from 'react';
3
+ import { forwardRef, useContext, useRef, useCallback } from 'react';
4
4
  import { radioClasses } from '@mezzanine-ui/core/radio';
5
5
  import InputCheck from '../_internal/InputCheck/InputCheck.js';
6
6
  import { useRadioControlValue } from '../Form/useRadioControlValue.js';
@@ -10,13 +10,43 @@ import Input from '../Input/Input.js';
10
10
  import cx from 'clsx';
11
11
 
12
12
  /**
13
- * The react component for `mezzanine` radio.
13
+ * 單選按鈕元件,支援標準(radio)與區段(segment)兩種類型。
14
+ *
15
+ * 在 `RadioGroup` 內使用時,會自動繼承群組的 `name`、`size` 與 `type`;
16
+ * 也可獨立使用,透過 `checked`/`defaultChecked` 進行受控或非受控操作。
17
+ * `segment` 類型可搭配 `icon` 屬性顯示圖示,適合用於分頁切換情境。
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * import Radio from '@mezzanine-ui/react/Radio';
22
+ *
23
+ * // 基本用法(非受控)
24
+ * <Radio value="male" inputProps={{ name: 'gender' }}>男性</Radio>
25
+ *
26
+ * // 受控用法
27
+ * const [value, setValue] = useState('a');
28
+ * <Radio
29
+ * checked={value === 'a'}
30
+ * value="a"
31
+ * inputProps={{ name: 'option' }}
32
+ * onChange={() => setValue('a')}
33
+ * >
34
+ * 選項 A
35
+ * </Radio>
36
+ *
37
+ * // Segment 類型搭配圖示
38
+ * import { ListIcon } from '@mezzanine-ui/icons';
39
+ * <Radio type="segment" icon={ListIcon} value="list">列表</Radio>
40
+ * ```
41
+ *
42
+ * @see {@link RadioGroup} 管理多個單選按鈕的群組元件
43
+ * @see {@link useRadioControlValue} 單選按鈕受控值的自訂 Hook
14
44
  */
15
45
  const Radio = forwardRef(function Radio(props, ref) {
16
- var _a, _b;
46
+ var _a, _b, _c;
17
47
  const radioGroup = useContext(RadioGroupContext);
18
48
  const { disabled: disabledFromGroup, name: nameFromGroup, size: sizeFromGroup, type: typeFromGroup, } = radioGroup || {};
19
- const { checked: checkedProp, className, children, defaultChecked, disabled = disabledFromGroup || false, error = false, icon, hint, inputProps, onChange: onChangeProp, size = sizeFromGroup || 'main', type = typeFromGroup || 'radio', value, withInputConfig, ...rest } = props;
49
+ const { checked: checkedProp, className, children, defaultChecked, disabled = disabledFromGroup || false, error = false, icon, hint, inputProps, onChange: onChangeProp, size: sizeProp, type = typeFromGroup || 'radio', value, withInputConfig, ...rest } = props;
20
50
  const { id: inputId, name = nameFromGroup, ...restInputProps } = inputProps || {};
21
51
  const [checked, onChange] = useRadioControlValue({
22
52
  checked: checkedProp,
@@ -25,20 +55,28 @@ const Radio = forwardRef(function Radio(props, ref) {
25
55
  radioGroup,
26
56
  value,
27
57
  });
28
- const [focused, setFocused] = useState(false);
58
+ const size = (_a = sizeProp !== null && sizeProp !== void 0 ? sizeProp : sizeFromGroup) !== null && _a !== void 0 ? _a : 'main';
59
+ const radioInputRef = useRef(null);
60
+ const textInputRef = useRef(null);
61
+ const handleRadioChange = useCallback((event) => {
62
+ var _a;
63
+ onChange(event);
64
+ if (withInputConfig && !withInputConfig.disabled) {
65
+ (_a = textInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
66
+ }
67
+ }, [onChange, withInputConfig]);
29
68
  return (jsxs("div", { ref: ref, className: cx(radioClasses.wrapper, className), children: [jsx(InputCheck, { ...rest, control: jsxs("span", { className: cx(radioClasses.host, radioClasses.size(size), {
30
69
  [radioClasses.segmented]: type === 'segment',
31
70
  [radioClasses.checked]: checked,
32
- [radioClasses.focused]: focused,
33
71
  [radioClasses.error]: error,
34
72
  }), children: [type === 'segment' && (jsxs("span", { className: cx(radioClasses.segmentedContainer, {
35
- [radioClasses.segmentedContainerHaveMinWidth]: !!children,
36
73
  [radioClasses.segmentedContainerWithIconText]: !!children && !!icon,
37
- }), children: [icon && jsx(Icon, { icon: icon, size: 16 }), children] })), jsx("input", { ...restInputProps, "aria-checked": checked, "aria-disabled": disabled, checked: checked, disabled: disabled, id: inputId, onChange: onChange, onFocus: () => {
38
- setFocused(true);
39
- }, onBlur: () => {
40
- setFocused(false);
41
- }, name: name, type: "radio", value: value })] }), disabled: disabled, error: error, focused: focused, hint: hint, htmlFor: inputId, segmentedStyle: type === 'segment', size: size, children: type === 'radio' && children }), type === 'radio' && withInputConfig && (jsx("div", { style: { width: (_a = withInputConfig.width) !== null && _a !== void 0 ? _a : 120 }, children: jsx(Input, { ...withInputConfig, variant: "base", placeholder: (_b = withInputConfig.placeholder) !== null && _b !== void 0 ? _b : 'Placeholder' }) }))] }));
74
+ }), children: [icon && jsx(Icon, { icon: icon, size: 16 }), children] })), jsx("input", { ...restInputProps, "aria-checked": checked, "aria-disabled": disabled, checked: checked, disabled: disabled, id: inputId, onChange: handleRadioChange, name: name, ref: radioInputRef, type: "radio", value: value })] }), disabled: disabled, error: error, hint: hint, htmlFor: inputId, segmentedStyle: type === 'segment', size: size, children: type === 'radio' && children }), type === 'radio' && withInputConfig && (jsx("div", { style: { width: (_b = withInputConfig.width) !== null && _b !== void 0 ? _b : 120 }, children: jsx(Input, { ...withInputConfig, inputRef: textInputRef, inputProps: {
75
+ onClick: () => {
76
+ var _a;
77
+ (_a = radioInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
78
+ },
79
+ }, variant: "base", placeholder: (_c = withInputConfig.placeholder) !== null && _c !== void 0 ? _c : 'Placeholder' }) }))] }));
42
80
  });
43
81
 
44
82
  export { Radio as default };
@@ -1,4 +1,4 @@
1
- import { RadioSize } from '@mezzanine-ui/core/radio';
1
+ import { InputCheckSize } from '@mezzanine-ui/core/_internal/input-check';
2
2
  import { ChangeEventHandler, ReactNode } from 'react';
3
3
  import { InputCheckGroupProps } from '../_internal/InputCheck/InputCheckGroup';
4
4
  import { RadioNormalProps, RadioSegmentProps } from './Radio';
@@ -38,7 +38,7 @@ export interface RadioGroupBaseProps extends Omit<InputCheckGroupProps, 'onChang
38
38
  * The size of radio group.
39
39
  * Control the size of radios in group if size not passed to radio.
40
40
  */
41
- size?: RadioSize;
41
+ size?: InputCheckSize;
42
42
  /**
43
43
  * The value of radio group.
44
44
  */
@@ -1,9 +1,10 @@
1
- import { RadioSize, RadioType } from '@mezzanine-ui/core/radio';
1
+ import { RadioType } from '@mezzanine-ui/core/radio';
2
+ import { InputCheckSize } from '@mezzanine-ui/core/_internal/input-check';
2
3
  import { RadioGroupControlContextValue } from '../Form/useRadioControlValue';
3
4
  export interface RadioGroupContextValue extends RadioGroupControlContextValue {
4
5
  disabled?: boolean;
5
6
  name?: string;
6
- size?: RadioSize;
7
+ size?: InputCheckSize;
7
8
  type?: RadioType;
8
9
  }
9
10
  export declare const RadioGroupContext: import("react").Context<RadioGroupContextValue | undefined>;
@@ -0,0 +1,20 @@
1
+ import { HTMLAttributes } from 'react';
2
+ export interface SectionGroupProps extends HTMLAttributes<HTMLDivElement> {
3
+ /**
4
+ * Additional style for the section group container.
5
+ */
6
+ className?: string;
7
+ /**
8
+ * Layout direction of the section group.
9
+ * @default 'vertical'
10
+ */
11
+ direction?: 'horizontal' | 'vertical';
12
+ }
13
+ /**
14
+ * The react component for `mezzanine` section group.
15
+ * Use this to compose multiple sections with consistent gap.
16
+ */
17
+ declare const SectionGroup: import("react").ForwardRefExoticComponent<SectionGroupProps & {
18
+ children?: import("react").ReactNode | undefined;
19
+ } & import("react").RefAttributes<HTMLDivElement>>;
20
+ export default SectionGroup;
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { forwardRef } from 'react';
4
+ import { sectionGroupClasses } from '@mezzanine-ui/core/section';
5
+ import cx from 'clsx';
6
+
7
+ /**
8
+ * The react component for `mezzanine` section group.
9
+ * Use this to compose multiple sections with consistent gap.
10
+ */
11
+ const SectionGroup = forwardRef(function SectionGroup(props, ref) {
12
+ const { children, className, direction = 'vertical', ...rest } = props;
13
+ return (jsx("div", { className: cx(sectionGroupClasses.host, direction === 'horizontal' && sectionGroupClasses.hostHorizontal, className), ref: ref, ...rest, children: children }));
14
+ });
15
+
16
+ export { SectionGroup as default };