@mezzanine-ui/react 1.0.0-beta.2 → 1.0.0-beta.4

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 (193) hide show
  1. package/Anchor/Anchor.d.ts +51 -18
  2. package/Anchor/Anchor.js +15 -15
  3. package/Anchor/AnchorGroup.d.ts +34 -0
  4. package/Anchor/AnchorGroup.js +37 -0
  5. package/Anchor/AnchorItem.d.ts +30 -0
  6. package/Anchor/AnchorItem.js +65 -0
  7. package/Anchor/index.d.ts +2 -0
  8. package/Anchor/index.js +1 -0
  9. package/Anchor/utils.d.ts +13 -0
  10. package/Anchor/utils.js +95 -0
  11. package/AutoComplete/AutoComplete.d.ts +217 -0
  12. package/AutoComplete/AutoComplete.js +433 -0
  13. package/AutoComplete/index.d.ts +2 -0
  14. package/AutoComplete/index.js +1 -0
  15. package/AutoComplete/useAutoCompleteCreation.d.ts +33 -0
  16. package/AutoComplete/useAutoCompleteCreation.js +201 -0
  17. package/AutoComplete/useAutoCompleteKeyboard.d.ts +31 -0
  18. package/AutoComplete/useAutoCompleteKeyboard.js +149 -0
  19. package/AutoComplete/useAutoCompleteSearch.d.ts +16 -0
  20. package/AutoComplete/useAutoCompleteSearch.js +69 -0
  21. package/AutoComplete/useCreationTracker.d.ts +17 -0
  22. package/AutoComplete/useCreationTracker.js +47 -0
  23. package/Breadcrumb/Breadcrumb.js +16 -21
  24. package/Breadcrumb/BreadcrumbDropdown.d.ts +11 -0
  25. package/Breadcrumb/BreadcrumbDropdown.js +22 -0
  26. package/Breadcrumb/BreadcrumbItem.d.ts +2 -3
  27. package/Breadcrumb/BreadcrumbItem.js +13 -31
  28. package/Breadcrumb/BreadcrumbOverflowMenu.d.ts +7 -0
  29. package/Breadcrumb/BreadcrumbOverflowMenu.js +77 -0
  30. package/Breadcrumb/BreadcrumbOverflowMenuDropdown.d.ts +11 -0
  31. package/Breadcrumb/BreadcrumbOverflowMenuDropdown.js +21 -0
  32. package/Breadcrumb/BreadcrumbOverflowMenuItem.d.ts +3 -0
  33. package/Breadcrumb/BreadcrumbOverflowMenuItem.js +27 -0
  34. package/Breadcrumb/typings.d.ts +21 -39
  35. package/Button/Button.js +13 -11
  36. package/Button/index.d.ts +1 -1
  37. package/Button/typings.d.ts +27 -4
  38. package/Checkbox/index.d.ts +4 -5
  39. package/Checkbox/index.js +1 -5
  40. package/ContentHeader/ContentHeader.d.ts +160 -0
  41. package/ContentHeader/ContentHeader.js +54 -0
  42. package/ContentHeader/index.d.ts +2 -0
  43. package/ContentHeader/index.js +1 -0
  44. package/ContentHeader/utils.d.ts +23 -0
  45. package/ContentHeader/utils.js +215 -0
  46. package/Description/Description.d.ts +12 -22
  47. package/Description/Description.js +4 -24
  48. package/Dropdown/Dropdown.d.ts +46 -1
  49. package/Dropdown/Dropdown.js +99 -14
  50. package/Dropdown/DropdownAction.d.ts +1 -1
  51. package/Dropdown/DropdownAction.js +1 -4
  52. package/Dropdown/DropdownItem.d.ts +28 -1
  53. package/Dropdown/DropdownItem.js +56 -14
  54. package/Dropdown/DropdownItemCard.d.ts +2 -2
  55. package/Dropdown/DropdownItemCard.js +20 -16
  56. package/Dropdown/DropdownStatus.js +29 -0
  57. package/Dropdown/dropdownKeydownHandler.d.ts +2 -1
  58. package/Dropdown/dropdownKeydownHandler.js +73 -0
  59. package/Dropdown/highlightText.js +5 -1
  60. package/Dropdown/shortcutTextHandler.d.ts +24 -0
  61. package/Dropdown/shortcutTextHandler.js +171 -0
  62. package/Empty/Empty.js +2 -1
  63. package/Empty/icons/EmptyMainNotificationIcon.d.ts +4 -0
  64. package/Empty/icons/EmptyMainNotificationIcon.js +9 -0
  65. package/Empty/typings.d.ts +2 -2
  66. package/FilterArea/Filter.d.ts +32 -0
  67. package/FilterArea/Filter.js +23 -0
  68. package/FilterArea/FilterArea.d.ts +58 -0
  69. package/FilterArea/FilterArea.js +31 -0
  70. package/FilterArea/FilterLine.d.ts +11 -0
  71. package/FilterArea/FilterLine.js +13 -0
  72. package/FilterArea/index.d.ts +6 -0
  73. package/FilterArea/index.js +3 -0
  74. package/Form/FormField.js +3 -1
  75. package/Input/Input.d.ts +35 -7
  76. package/Input/Input.js +48 -14
  77. package/Input/index.d.ts +1 -1
  78. package/Modal/MediaPreviewModal.d.ts +54 -0
  79. package/Modal/MediaPreviewModal.js +158 -0
  80. package/Modal/Modal.d.ts +103 -11
  81. package/Modal/Modal.js +14 -9
  82. package/Modal/ModalBodyForVerification.d.ts +59 -0
  83. package/Modal/ModalBodyForVerification.js +99 -0
  84. package/Modal/ModalControl.d.ts +2 -2
  85. package/Modal/ModalControl.js +1 -1
  86. package/Modal/ModalFooter.d.ts +119 -1
  87. package/Modal/ModalFooter.js +15 -3
  88. package/Modal/ModalHeader.d.ts +26 -7
  89. package/Modal/ModalHeader.js +33 -7
  90. package/Modal/index.d.ts +6 -5
  91. package/Modal/index.js +2 -2
  92. package/Modal/useModalContainer.d.ts +12 -3
  93. package/Modal/useModalContainer.js +28 -6
  94. package/Navigation/Navigation.d.ts +7 -2
  95. package/Navigation/Navigation.js +36 -35
  96. package/Navigation/NavigationHeader.d.ts +4 -0
  97. package/Navigation/NavigationHeader.js +3 -2
  98. package/Navigation/NavigationOption.d.ts +8 -3
  99. package/Navigation/NavigationOption.js +46 -11
  100. package/Navigation/NavigationOptionCategory.js +1 -0
  101. package/Navigation/NavigationOverflowMenu.d.ts +6 -0
  102. package/Navigation/NavigationOverflowMenu.js +90 -0
  103. package/Navigation/NavigationOverflowMenuOption.d.ts +7 -0
  104. package/Navigation/NavigationOverflowMenuOption.js +68 -0
  105. package/Navigation/NavigationUserMenu.d.ts +4 -2
  106. package/Navigation/NavigationUserMenu.js +13 -5
  107. package/Navigation/context.d.ts +3 -2
  108. package/Navigation/useVisibleItems.d.ts +5 -0
  109. package/Navigation/useVisibleItems.js +54 -0
  110. package/NotificationCenter/NotificationCenter.d.ts +124 -0
  111. package/NotificationCenter/NotificationCenter.js +279 -0
  112. package/NotificationCenter/NotificationCenterDrawer.d.ts +109 -0
  113. package/NotificationCenter/index.d.ts +3 -0
  114. package/NotificationCenter/index.js +1 -0
  115. package/PageFooter/PageFooter.d.ts +19 -9
  116. package/PageFooter/PageFooter.js +10 -10
  117. package/PageHeader/PageHeader.d.ts +32 -25
  118. package/PageHeader/PageHeader.js +49 -43
  119. package/ResultState/ResultState.d.ts +9 -0
  120. package/ResultState/ResultState.js +36 -4
  121. package/Scrollbar/Scrollbar.d.ts +9 -0
  122. package/Scrollbar/Scrollbar.js +78 -0
  123. package/Scrollbar/index.d.ts +2 -0
  124. package/Scrollbar/index.js +1 -0
  125. package/Scrollbar/typings.d.ts +47 -0
  126. package/Select/SelectTrigger.js +5 -4
  127. package/Select/index.d.ts +0 -2
  128. package/Select/index.js +0 -1
  129. package/Select/typings.d.ts +6 -1
  130. package/Selection/Selection.js +1 -1
  131. package/Selection/SelectionGroup.d.ts +28 -0
  132. package/Slider/useSlider.js +1 -1
  133. package/Table/Table.d.ts +2 -120
  134. package/Table/Table.js +148 -53
  135. package/Table/TableContext.d.ts +11 -12
  136. package/Table/components/TableActionsCell.js +12 -4
  137. package/Table/components/TableBody.js +2 -1
  138. package/Table/components/TableBulkActions.js +1 -19
  139. package/Table/components/TableColGroup.d.ts +1 -4
  140. package/Table/components/TableColGroup.js +15 -16
  141. package/Table/components/TableCollectableCell.d.ts +17 -0
  142. package/Table/components/TableCollectableCell.js +54 -0
  143. package/Table/components/TableDragOrPinHandleCell.d.ts +20 -0
  144. package/Table/components/TableDragOrPinHandleCell.js +58 -0
  145. package/Table/components/TableExpandedRow.js +11 -2
  146. package/Table/components/TableHeader.js +12 -10
  147. package/Table/components/TableRow.js +38 -13
  148. package/Table/components/TableSelectionCell.js +1 -1
  149. package/Table/components/TableToggleableCell.d.ts +16 -0
  150. package/Table/components/TableToggleableCell.js +51 -0
  151. package/Table/components/index.d.ts +4 -1
  152. package/Table/components/index.js +3 -0
  153. package/Table/hooks/typings.d.ts +18 -4
  154. package/Table/hooks/useTableExpansion.d.ts +2 -2
  155. package/Table/hooks/useTableExpansion.js +5 -5
  156. package/Table/hooks/useTableFixedOffsets.d.ts +6 -2
  157. package/Table/hooks/useTableFixedOffsets.js +60 -26
  158. package/Table/hooks/useTableScroll.d.ts +9 -3
  159. package/Table/hooks/useTableScroll.js +34 -7
  160. package/Table/hooks/useTableVirtualization.d.ts +2 -1
  161. package/Table/hooks/useTableVirtualization.js +2 -8
  162. package/Table/index.d.ts +4 -3
  163. package/Table/index.js +3 -0
  164. package/Table/typings.d.ts +172 -0
  165. package/Table/utils/useTableRowSelection.js +13 -5
  166. package/Tag/TagGroup.d.ts +3 -0
  167. package/Tag/index.d.ts +2 -0
  168. package/Tag/index.js +1 -0
  169. package/Transition/Slide.d.ts +9 -2
  170. package/Transition/Slide.js +7 -4
  171. package/Tree/TreeNode.js +1 -1
  172. package/Upload/UploadPictureCard.js +1 -1
  173. package/index.d.ts +37 -21
  174. package/index.js +25 -11
  175. package/package.json +6 -4
  176. package/Modal/ModalActions.d.ts +0 -9
  177. package/Modal/ModalActions.js +0 -20
  178. package/Modal/ModalBody.d.ts +0 -7
  179. package/Modal/ModalBody.js +0 -14
  180. package/Notification/Notification.d.ts +0 -54
  181. package/Notification/Notification.js +0 -76
  182. package/Notification/index.d.ts +0 -3
  183. package/Notification/index.js +0 -1
  184. package/PageToolbar/PageToolbar.d.ts +0 -114
  185. package/PageToolbar/PageToolbar.js +0 -23
  186. package/PageToolbar/index.d.ts +0 -2
  187. package/PageToolbar/index.js +0 -1
  188. package/PageToolbar/utils.d.ts +0 -23
  189. package/PageToolbar/utils.js +0 -165
  190. package/Select/AutoComplete.d.ts +0 -107
  191. package/Select/AutoComplete.js +0 -114
  192. package/Table/components/TableDragHandleCell.d.ts +0 -11
  193. package/Table/components/TableDragHandleCell.js +0 -44
@@ -0,0 +1,215 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { isValidElement, cloneElement, Children } from 'react';
3
+ import Button from '../Button/Button.js';
4
+ import { flattenChildren } from '../utils/flatten-children.js';
5
+ import { ChevronLeftIcon } from '@mezzanine-ui/icons';
6
+ import Input from '../Input/Input.js';
7
+ import Select from '../Select/Select.js';
8
+ import Dropdown from '../Dropdown/Dropdown.js';
9
+
10
+ /**
11
+ * Renders a button from either ButtonProps or a React element.
12
+ * Applies the specified size and variant to the button.
13
+ */
14
+ const renderButton = (button, size) => {
15
+ if (!button) {
16
+ return null;
17
+ }
18
+ if (isValidElement(button)) {
19
+ return cloneElement(button, {
20
+ size,
21
+ type: 'button',
22
+ });
23
+ }
24
+ return jsx(Button, { ...button, size: size, type: "button" });
25
+ };
26
+ const withSize = (target, size) => {
27
+ return cloneElement(target, { size });
28
+ };
29
+ const renderFilterProp = (prop, size) => {
30
+ if (!prop) {
31
+ return null;
32
+ }
33
+ const { variant } = prop;
34
+ if (variant === 'search') {
35
+ return (jsx(Input, { ...prop, size: size, variant: "search" }));
36
+ }
37
+ if (variant === 'select') {
38
+ return jsx(Select, { ...prop, size: size });
39
+ }
40
+ if (variant === 'segmentedControl') {
41
+ console.warn('SegmentedControl component is not implemented yet.');
42
+ return null;
43
+ }
44
+ return null;
45
+ };
46
+ const renderIconButtonWithProps = (child, size) => {
47
+ const { icon } = child.props;
48
+ return cloneElement(child, {
49
+ icon,
50
+ iconType: 'icon-only',
51
+ size,
52
+ variant: 'base-secondary',
53
+ type: 'button',
54
+ });
55
+ };
56
+ const renderIconButtonsProp = (utilities, size) => {
57
+ const result = [];
58
+ utilities === null || utilities === void 0 ? void 0 : utilities.forEach((props) => {
59
+ if (props instanceof Object && 'icon' in props) {
60
+ result.push(jsx(Button, { ...props, type: "button", size: size, iconType: "icon-only", variant: "base-secondary" }));
61
+ }
62
+ if (props instanceof Object && 'options' in props) {
63
+ if (!isValidElement(props.children) ||
64
+ !(props.children.type === Button)) {
65
+ console.warn('[Mezzanine][ContentHeader]: Dropdown in utilities should have Button with icon as its children.');
66
+ return;
67
+ }
68
+ result.push(jsx(Dropdown, { ...props, children: cloneElement(props.children, {
69
+ type: 'button',
70
+ size: size,
71
+ iconType: 'icon-only',
72
+ variant: 'base-secondary',
73
+ }) }));
74
+ }
75
+ });
76
+ return result;
77
+ };
78
+ const variantOrder = {
79
+ 'destructive-secondary': 0,
80
+ 'base-secondary': 1,
81
+ 'base-primary': 2,
82
+ // undefined: 2,
83
+ 'base-tertiary': 0,
84
+ 'base-ghost': 0,
85
+ 'base-dashed': 0,
86
+ 'base-text-link': 0,
87
+ 'destructive-primary': 0,
88
+ 'destructive-ghost': 0,
89
+ 'destructive-text-link': 0,
90
+ inverse: 0,
91
+ 'inverse-ghost': 0,
92
+ };
93
+ /**
94
+ * Renders action buttons based on the actions configuration.
95
+ * Supports both structured actions object and single button element/props.
96
+ */
97
+ const renderActionsProp = (actions, size) => {
98
+ if (actions) {
99
+ return actions
100
+ .filter((v) => {
101
+ if (v.variant === 'destructive-secondary' ||
102
+ v.variant === 'base-secondary' ||
103
+ v.variant === 'base-primary' ||
104
+ v.variant === undefined) {
105
+ return true;
106
+ }
107
+ else {
108
+ console.warn(`[Mezzanine][ContentHeader]: Button with variant "${v.variant}" will not be rendered in ContentHeader actions.`);
109
+ return false;
110
+ }
111
+ })
112
+ .sort((a, b) => variantOrder[a.variant || 'base-primary'] -
113
+ variantOrder[b.variant || 'base-primary'])
114
+ .map((v) => renderButton(v, size));
115
+ }
116
+ return null;
117
+ };
118
+ const resolveContentHeaderChild = (children, size) => {
119
+ let filter = null;
120
+ // [destructive-secondary[], base-secondary[], base-primary[]]
121
+ const actionsWithOrder = [[], [], []];
122
+ const utilities = [];
123
+ let backButton = null;
124
+ if (children) {
125
+ const flatChildren = flattenChildren(children);
126
+ Children.forEach(flatChildren, (child) => {
127
+ if (!isValidElement(child)) {
128
+ return;
129
+ }
130
+ const { type, props } = child;
131
+ if (type === 'a' || props.href) {
132
+ backButton = cloneElement(child, {
133
+ children: (jsx(Button, { component: 'span', iconType: "icon-only", icon: ChevronLeftIcon, "aria-label": "Back", type: "button", size: "sub", variant: "base-tertiary" })),
134
+ });
135
+ return;
136
+ }
137
+ const sizeProp = props.size;
138
+ if (sizeProp !== undefined && sizeProp !== size) {
139
+ console.warn('[Mezzanine][ContentHeader]: Input, Button, Select size in ContentHeader utilities is forced to match ContentHeader size.');
140
+ }
141
+ // is filter
142
+ if ((type === Input && props.variant === 'search') ||
143
+ type === Select) {
144
+ if (filter) {
145
+ console.warn('[Mezzanine][ContentHeader]: ContentHeader only accepts one filter component.');
146
+ }
147
+ filter = withSize(child, size);
148
+ }
149
+ else if (type.toString() === 'SegmentedControl') {
150
+ console.warn('SegmentedControl component is not implemented yet.');
151
+ }
152
+ // is utilities (icon button)
153
+ else if ((type === Button && props.iconType === 'icon-only') ||
154
+ (type === Button &&
155
+ props.icon &&
156
+ !props.children)) {
157
+ utilities.push(renderIconButtonWithProps(child, size));
158
+ }
159
+ else if (type === Dropdown) {
160
+ const childProps = child.props
161
+ .children;
162
+ if (!isValidElement(childProps) || childProps.type !== Button) {
163
+ console.warn('[Mezzanine][ContentHeader]: Dropdown in utilities should have Button with icon as its children.');
164
+ return;
165
+ }
166
+ utilities.push(cloneElement(child, {
167
+ children: renderIconButtonWithProps(child.props
168
+ .children, size),
169
+ }));
170
+ }
171
+ // is actions (normal button)
172
+ else if (type === Button) {
173
+ const variant = props.variant;
174
+ if (variant !== 'base-primary' &&
175
+ variant !== 'base-secondary' &&
176
+ variant !== 'destructive-secondary' &&
177
+ variant !== undefined) {
178
+ console.warn(`[Mezzanine][ContentHeader]: Button with variant "${variant}" will not be rendered in ContentHeader actions.`);
179
+ return;
180
+ }
181
+ const buttonElement = renderButton(child, size);
182
+ if (!buttonElement) {
183
+ return;
184
+ }
185
+ if (variant === 'destructive-secondary') {
186
+ actionsWithOrder[0].push(buttonElement);
187
+ }
188
+ else if (variant === 'base-secondary') {
189
+ actionsWithOrder[1].push(buttonElement);
190
+ }
191
+ else if (variant === 'base-primary') {
192
+ actionsWithOrder[2].push(buttonElement);
193
+ }
194
+ else if (variant === undefined) {
195
+ actionsWithOrder[2].push(buttonElement);
196
+ }
197
+ }
198
+ else {
199
+ console.warn('[Mezzanine][ContentHeader]: ContentHeader only accepts Input (search variant), Select, SegmentedControl, Dropdown with Icon Button, or Button as children.');
200
+ }
201
+ });
202
+ }
203
+ return {
204
+ filter,
205
+ actions: [
206
+ ...actionsWithOrder[0],
207
+ ...actionsWithOrder[1],
208
+ ...actionsWithOrder[2],
209
+ ],
210
+ utilities,
211
+ backButton,
212
+ };
213
+ };
214
+
215
+ export { renderActionsProp, renderButton, renderFilterProp, renderIconButtonWithProps, renderIconButtonsProp, resolveContentHeaderChild };
@@ -1,40 +1,30 @@
1
- import { DescriptionContentVariant, DescriptionOrientation } from '@mezzanine-ui/core/description';
1
+ import { ReactElement } from 'react';
2
+ import { DescriptionOrientation } from '@mezzanine-ui/core/description';
2
3
  import { DescriptionTitleProps } from './DescriptionTitle';
3
4
  import { DescriptionContentProps } from './DescriptionContent';
4
5
  import { BadgeProps } from '../Badge/typings';
5
6
  import { ButtonProps } from '../Button';
6
7
  import { ProgressProps } from '../Progress';
7
- import { TagProps } from '../Tag/typings';
8
- export interface DescriptionProps {
8
+ import { TagGroupProps } from '../Tag/TagGroup';
9
+ type DistributiveOmit<T, K extends PropertyKey> = T extends any ? Omit<T, K> : never;
10
+ export type DescriptionProps = DistributiveOmit<DescriptionTitleProps, 'className' | 'children'> & {
9
11
  /**
10
- * Custom class name for description
12
+ * Defines what is rendered as the description content
11
13
  */
12
- className?: string;
14
+ children: ReactElement<DescriptionContentProps> | ReactElement<BadgeProps> | ReactElement<ButtonProps> | ReactElement<ProgressProps> | ReactElement<TagGroupProps>;
13
15
  /**
14
- * Defines what is rendered as the description content
16
+ * Custom class name for description
15
17
  */
16
- contentProps: DescriptionContentProps | {
17
- variant: Extract<DescriptionContentVariant, 'badge'>;
18
- badge: BadgeProps;
19
- } | {
20
- variant: Extract<DescriptionContentVariant, 'button'>;
21
- button: ButtonProps;
22
- } | {
23
- variant: Extract<DescriptionContentVariant, 'progress'>;
24
- progress: ProgressProps;
25
- } | {
26
- variant: Extract<DescriptionContentVariant, 'tags'>;
27
- tags: TagProps[];
28
- };
18
+ className?: string;
29
19
  /**
30
20
  * Define the layout direction between the title and the content
31
21
  * @default 'horizontal'
32
22
  */
33
23
  orientation?: DescriptionOrientation;
34
24
  /**
35
- * Props passed to the DescriptionTitle component
25
+ * title text for description
36
26
  */
37
- titleProps: DescriptionTitleProps;
38
- }
27
+ title: string;
28
+ };
39
29
  declare const Description: import("react").ForwardRefExoticComponent<DescriptionProps & import("react").RefAttributes<HTMLDivElement>>;
40
30
  export default Description;
@@ -1,33 +1,13 @@
1
1
  'use client';
2
- import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { forwardRef, useMemo } from 'react';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { forwardRef } from 'react';
4
4
  import { descriptionClasses } from '@mezzanine-ui/core/description';
5
5
  import DescriptionTitle from './DescriptionTitle.js';
6
- import DescriptionContent from './DescriptionContent.js';
7
- import Button from '../Button/Button.js';
8
- import TagGroup from '../Tag/TagGroup.js';
9
- import Tag from '../Tag/Tag.js';
10
- import Progress from '../Progress/Progress.js';
11
- import Badge from '../Badge/Badge.js';
12
6
  import cx from 'clsx';
13
7
 
14
8
  const Description = forwardRef(function Description(props, ref) {
15
- const { className, contentProps, orientation = 'horizontal', titleProps, } = props;
16
- const contentComponent = useMemo(() => {
17
- switch (contentProps.variant) {
18
- case 'badge':
19
- return jsx(Badge, { ...contentProps.badge });
20
- case 'button':
21
- return jsx(Button, { ...contentProps.button });
22
- case 'progress':
23
- return jsx(Progress, { ...contentProps.progress });
24
- case 'tags':
25
- return (jsx(TagGroup, { children: contentProps.tags.map((tagProps, index) => (jsx(Tag, { ...tagProps }, `${tagProps.label}-${index}`))) }));
26
- default:
27
- return jsx(DescriptionContent, { ...contentProps });
28
- }
29
- }, [contentProps]);
30
- return (jsxs("div", { className: cx(descriptionClasses.host, descriptionClasses.orientation(orientation), className), ref: ref, children: [jsx(DescriptionTitle, { ...titleProps }), contentComponent] }));
9
+ const { children, className, orientation = 'horizontal', title, ...rest } = props;
10
+ return (jsxs("div", { className: cx(descriptionClasses.host, descriptionClasses.orientation(orientation), className), ref: ref, children: [jsx(DescriptionTitle, { ...rest, children: title }), children] }));
31
11
  });
32
12
 
33
13
  export { Description as default };
@@ -1,8 +1,9 @@
1
1
  import { ReactElement } from 'react';
2
- import { DropdownInputPosition, DropdownItemSharedProps, DropdownOption, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
2
+ import { DropdownInputPosition, DropdownItemSharedProps, DropdownOption, DropdownStatus as DropdownStatusType, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
3
3
  import { ButtonProps } from '../Button';
4
4
  import { InputProps } from '../Input';
5
5
  import { PopperPlacement } from '../Popper';
6
+ import { IconDefinition } from '@mezzanine-ui/icons';
6
7
  export interface DropdownProps extends DropdownItemSharedProps {
7
8
  /**
8
9
  * The text of the cancel button.
@@ -51,6 +52,11 @@ export interface DropdownProps extends DropdownItemSharedProps {
51
52
  * @default false
52
53
  */
53
54
  isMatchInputValue?: boolean;
55
+ /**
56
+ * The text to follow for highlighting in dropdown options.
57
+ * If provided, this will be used instead of auto-extracting from children props.
58
+ */
59
+ followText?: string;
54
60
  /**
55
61
  * The listbox id of the dropdown.
56
62
  */
@@ -112,6 +118,12 @@ export interface DropdownProps extends DropdownItemSharedProps {
112
118
  * The placement of the dropdown.
113
119
  */
114
120
  placement?: PopperPlacement;
121
+ /**
122
+ * Custom width for the dropdown.
123
+ * Can be a number (pixels) or a string (e.g., '200px', '50%').
124
+ * If provided, this takes precedence over `sameWidth`.
125
+ */
126
+ customWidth?: number | string;
115
127
  /**
116
128
  * Whether to set the same width as its anchor element.
117
129
  * @default false
@@ -134,5 +146,38 @@ export interface DropdownProps extends DropdownItemSharedProps {
134
146
  * The z-index of the dropdown.
135
147
  */
136
148
  zIndex?: number | string;
149
+ /**
150
+ * The status of the dropdown (loading or empty).
151
+ */
152
+ status?: DropdownStatusType;
153
+ /**
154
+ * The text of the dropdown loading status.
155
+ */
156
+ loadingText?: string;
157
+ /**
158
+ * The text of the dropdown empty status.
159
+ */
160
+ emptyText?: string;
161
+ /**
162
+ * The icon of the dropdown empty status.
163
+ */
164
+ emptyIcon?: IconDefinition;
165
+ /**
166
+ * Whether to disable portal.
167
+ * This prop is only relevant when `inputPosition` is set to 'outside'.
168
+ * Controls whether the dropdown content is rendered within the current hierarchy or portaled to the body.
169
+ * @default false
170
+ */
171
+ disablePortal?: boolean;
172
+ /**
173
+ * Callback fired when the dropdown list reaches the bottom.
174
+ * Only fires when `maxHeight` is set and the list is scrollable.
175
+ */
176
+ onReachBottom?: () => void;
177
+ /**
178
+ * Callback fired when the dropdown list leaves the bottom.
179
+ * Only fires when `maxHeight` is set and the list is scrollable.
180
+ */
181
+ onLeaveBottom?: () => void;
137
182
  }
138
183
  export default function Dropdown(props: DropdownProps): import("react/jsx-runtime").JSX.Element;
@@ -3,7 +3,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { useId, useMemo, useState, useRef, useCallback, useEffect, cloneElement, createElement } from 'react';
4
4
  import cx from 'clsx';
5
5
  import { dropdownClasses } from '@mezzanine-ui/core/dropdown/dropdown';
6
- import { size, offset } from '@floating-ui/react-dom';
6
+ import { size, offset, autoUpdate } from '@floating-ui/react-dom';
7
7
  import { MOTION_EASING, MOTION_DURATION } from '@mezzanine-ui/system/motion';
8
8
  import { TransitionGroup } from 'react-transition-group';
9
9
  import Button from '../Button/Button.js';
@@ -14,7 +14,7 @@ import DropdownItem from './DropdownItem.js';
14
14
  import Popper from '../Popper/Popper.js';
15
15
 
16
16
  function Dropdown(props) {
17
- const { activeIndex: activeIndexProp, id, children, options = [], type = 'default', maxHeight, disabled = false, showDropdownActions = false, actionCancelText, actionConfirmText, actionText, actionClearText, actionCustomButtonProps, showActionShowTopBar, isMatchInputValue = false, inputPosition = 'outside', placement = 'bottom', sameWidth = false, listboxId: listboxIdProp, listboxLabel, onClose, onOpen, open: openProp, onVisibilityChange, onSelect, onActionConfirm, onActionCancel, onActionCustom, onActionClear, onItemHover, zIndex, } = props;
17
+ const { activeIndex: activeIndexProp, id, children, options = [], type = 'default', maxHeight, disabled = false, showDropdownActions = false, actionCancelText, actionConfirmText, actionText, actionClearText, actionCustomButtonProps, showActionShowTopBar, isMatchInputValue = false, inputPosition = 'outside', placement = 'bottom', customWidth, sameWidth = false, listboxId: listboxIdProp, listboxLabel, onClose, onOpen, open: openProp, onVisibilityChange, onSelect, onActionConfirm, onActionCancel, onActionCustom, onActionClear, onItemHover, zIndex, status, loadingText, emptyText, emptyIcon, followText: followTextProp, disablePortal = false, onReachBottom, onLeaveBottom, mode, value, } = props;
18
18
  const isInline = inputPosition === 'inside';
19
19
  const inputId = useId();
20
20
  const defaultListboxId = `${inputId}-listbox`;
@@ -49,7 +49,9 @@ function Dropdown(props) {
49
49
  const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
50
50
  const isOpenControlled = openProp !== undefined;
51
51
  const isOpen = isOpenControlled ? !!openProp : uncontrolledOpen;
52
- const [uncontrolledActiveIndex, setUncontrolledActiveIndex] = useState(activeIndexProp !== null && activeIndexProp !== void 0 ? activeIndexProp : null);
52
+ // Keep setter for uncontrolled mode support (e.g., keyboard navigation)
53
+ // Currently not used in handleItemHover to prevent style conflicts
54
+ const [uncontrolledActiveIndex, _setUncontrolledActiveIndex] = useState(activeIndexProp !== null && activeIndexProp !== void 0 ? activeIndexProp : null);
53
55
  const isActiveIndexControlled = activeIndexProp !== undefined;
54
56
  const mergedActiveIndex = isActiveIndexControlled
55
57
  ? activeIndexProp
@@ -73,6 +75,11 @@ function Dropdown(props) {
73
75
  }), []);
74
76
  const followText = useMemo(() => {
75
77
  var _a, _b, _c, _d;
78
+ // If followText is explicitly provided, use it
79
+ if (followTextProp !== undefined) {
80
+ return followTextProp != null ? String(followTextProp) : undefined;
81
+ }
82
+ // Otherwise, auto-extract from children props
76
83
  if (children.type === Button) {
77
84
  return undefined;
78
85
  }
@@ -81,16 +88,35 @@ function Dropdown(props) {
81
88
  }
82
89
  // Try to get value from Input component props
83
90
  const inputValue = (_d = (_b = (_a = children.props) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : (_c = children.props) === null || _c === void 0 ? void 0 : _c.defaultValue) !== null && _d !== void 0 ? _d : '';
84
- return inputValue;
85
- }, [children, isMatchInputValue]);
91
+ // Ensure the value is a string or undefined
92
+ return inputValue != null ? String(inputValue) : undefined;
93
+ }, [children, isMatchInputValue, followTextProp]);
86
94
  const popoverPlacement = useMemo(() => {
87
95
  if (inputPosition === 'outside') {
88
96
  return placement;
89
97
  }
90
98
  return 'bottom';
91
99
  }, [inputPosition, placement]);
100
+ const customWidthMiddleware = useMemo(() => {
101
+ if (!customWidth) {
102
+ return null;
103
+ }
104
+ const widthValue = typeof customWidth === 'number'
105
+ ? `${customWidth}px`
106
+ : customWidth;
107
+ return {
108
+ name: 'customWidth',
109
+ fn: ({ elements }) => {
110
+ Object.assign(elements.floating.style, {
111
+ width: widthValue,
112
+ });
113
+ return {};
114
+ },
115
+ };
116
+ }, [customWidth]);
92
117
  const sameWidthMiddleware = useMemo(() => {
93
- if (!sameWidth) {
118
+ // If customWidth is set, don't apply sameWidth
119
+ if (customWidth || !sameWidth) {
94
120
  return null;
95
121
  }
96
122
  return size({
@@ -100,10 +126,26 @@ function Dropdown(props) {
100
126
  });
101
127
  },
102
128
  });
103
- }, [sameWidth]);
129
+ }, [customWidth, sameWidth]);
104
130
  const offsetMiddleware = useMemo(() => {
105
131
  return offset({ mainAxis: 4 });
106
132
  }, []);
133
+ // Set z-index for popper to ensure it appears above other elements
134
+ const zIndexMiddleware = useMemo(() => {
135
+ const zIndexValue = zIndex !== null && zIndex !== void 0 ? zIndex : 1;
136
+ return {
137
+ name: 'zIndex',
138
+ fn: ({ elements }) => {
139
+ const zIndexNum = typeof zIndexValue === 'number'
140
+ ? zIndexValue
141
+ : (typeof zIndexValue === 'string' ? parseInt(zIndexValue, 10) || zIndexValue : 1);
142
+ Object.assign(elements.floating.style, {
143
+ zIndex: zIndexNum,
144
+ });
145
+ return {};
146
+ },
147
+ };
148
+ }, [zIndex]);
107
149
  const prevIsOpenRef = useRef(isOpen);
108
150
  const translateFrom = useMemo(() => {
109
151
  if (isInline) {
@@ -134,6 +176,29 @@ function Dropdown(props) {
134
176
  }, [isOpen, onClose, onOpen]);
135
177
  const anchorRef = useRef(null);
136
178
  const popperRef = useRef(null);
179
+ const popperControllerRef = useRef(null);
180
+ // Auto-update popper position when anchor element size changes
181
+ useEffect(() => {
182
+ if (!isOpen || isInline || !anchorRef.current || !popperControllerRef.current) {
183
+ return;
184
+ }
185
+ const update = popperControllerRef.current.update;
186
+ if (!update) {
187
+ return;
188
+ }
189
+ // Get floating element from controller refs
190
+ // Check refs exists before accessing nested properties
191
+ const refs = popperControllerRef.current.refs;
192
+ if (!refs) {
193
+ return;
194
+ }
195
+ const floatingElement = refs.floating.current;
196
+ if (!floatingElement) {
197
+ return;
198
+ }
199
+ const cleanup = autoUpdate(anchorRef.current, floatingElement, update);
200
+ return cleanup;
201
+ }, [isOpen, isInline]);
137
202
  // Extract combobox props logic to avoid duplication
138
203
  const getComboboxProps = useMemo(() => {
139
204
  const childWithRef = children;
@@ -150,11 +215,8 @@ function Dropdown(props) {
150
215
  };
151
216
  }, [children, listboxId, isOpen, isMatchInputValue, ariaActivedescendant]);
152
217
  const handleItemHover = useCallback((index) => {
153
- if (!isActiveIndexControlled) {
154
- setUncontrolledActiveIndex(index);
155
- }
156
218
  onItemHover === null || onItemHover === void 0 ? void 0 : onItemHover(index);
157
- }, [isActiveIndexControlled, onItemHover]);
219
+ }, [onItemHover]);
158
220
  // Extract shared DropdownItem props to avoid duplication
159
221
  const baseDropdownItemProps = useMemo(() => ({
160
222
  actionConfig,
@@ -167,8 +229,16 @@ function Dropdown(props) {
167
229
  sameWidth,
168
230
  onHover: handleItemHover,
169
231
  onSelect,
232
+ onReachBottom,
233
+ onLeaveBottom,
170
234
  options,
171
235
  type,
236
+ status,
237
+ loadingText,
238
+ emptyText,
239
+ emptyIcon,
240
+ mode,
241
+ value,
172
242
  }), [
173
243
  actionConfig,
174
244
  mergedActiveIndex,
@@ -180,8 +250,16 @@ function Dropdown(props) {
180
250
  sameWidth,
181
251
  handleItemHover,
182
252
  onSelect,
253
+ onReachBottom,
254
+ onLeaveBottom,
183
255
  options,
184
256
  type,
257
+ status,
258
+ loadingText,
259
+ emptyText,
260
+ emptyIcon,
261
+ mode,
262
+ value,
185
263
  ]);
186
264
  const triggerElement = useMemo(() => {
187
265
  const childWithRef = children;
@@ -214,6 +292,11 @@ function Dropdown(props) {
214
292
  (_b = (_a = childWithRef.props) === null || _a === void 0 ? void 0 : _a.onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, event);
215
293
  if (event === null || event === void 0 ? void 0 : event.defaultPrevented)
216
294
  return;
295
+ // When open is controlled, don't automatically close on blur
296
+ // Let the controlled state handle the visibility
297
+ if (isOpenControlled) {
298
+ return;
299
+ }
217
300
  const nextFocusTarget = event === null || event === void 0 ? void 0 : event.relatedTarget;
218
301
  const container = containerRef.current;
219
302
  if (container &&
@@ -238,7 +321,7 @@ function Dropdown(props) {
238
321
  setOpen(true);
239
322
  },
240
323
  });
241
- }, [children, getComboboxProps, isInline, setOpen]);
324
+ }, [children, getComboboxProps, isInline, setOpen, isOpenControlled]);
242
325
  useDocumentEvents(() => {
243
326
  if (!isOpen) {
244
327
  return;
@@ -270,13 +353,15 @@ function Dropdown(props) {
270
353
  }, [isInline, isOpen, setOpen]);
271
354
  return (jsxs("div", { id: id, ref: containerRef, className: cx(dropdownClasses.root, dropdownClasses.inputPosition(inputPosition)), children: [isInline && (jsxs(TransitionGroup, { component: null, children: [!isOpen && inlineTriggerElement && (createElement(Translate, { ...translateProps, from: translateFrom, key: "inline-trigger", in: true },
272
355
  jsx("div", { children: inlineTriggerElement }))), isOpen && (createElement(Translate, { ...translateProps, from: translateFrom, key: "inline-list", in: true },
273
- jsx("div", { children: jsx(DropdownItem, { ...baseDropdownItemProps, headerContent: inlineTriggerElement }) })))] })), !isInline && (jsx(Popper, { ref: popperRef, anchor: anchorRef, open: isOpen, disablePortal: true, options: {
356
+ jsx("div", { children: jsx(DropdownItem, { ...baseDropdownItemProps, headerContent: inlineTriggerElement }) })))] })), !isInline && (jsx(Popper, { ref: popperRef, anchor: anchorRef, className: dropdownClasses.popperWithPortal, controllerRef: popperControllerRef, open: isOpen, disablePortal: disablePortal, options: {
274
357
  placement: popoverPlacement,
275
358
  middleware: [
276
359
  offsetMiddleware,
360
+ zIndexMiddleware,
361
+ ...(customWidthMiddleware ? [customWidthMiddleware] : []),
277
362
  ...(sameWidthMiddleware ? [sameWidthMiddleware] : []),
278
363
  ],
279
- }, style: zIndex ? { zIndex } : undefined, children: jsx(TransitionGroup, { component: null, children: isOpen && (createElement(Translate, { ...translateProps, from: translateFrom, key: "popper-list", in: true },
364
+ }, children: jsx(TransitionGroup, { component: null, children: isOpen && (createElement(Translate, { ...translateProps, from: translateFrom, key: "popper-list", in: true },
280
365
  jsx("div", { children: jsx(DropdownItem, { ...baseDropdownItemProps }) }))) }) })), !isInline && triggerElement] }));
281
366
  }
282
367
 
@@ -1,4 +1,4 @@
1
- import { ButtonProps } from "../Button";
1
+ import { ButtonProps } from '../Button';
2
2
  export interface DropdownActionProps {
3
3
  /**
4
4
  * The text of the custom action button.
@@ -17,10 +17,7 @@ function DropdownAction(props) {
17
17
  const isDefaultMode = !isClearMode && !isCustomMode;
18
18
  const hasCancel = Boolean(onCancel && isDefaultMode);
19
19
  const hasConfirm = Boolean(onConfirm && isDefaultMode);
20
- return (jsx(Fragment, { children: showActions && hasAnyEvent && (jsxs("div", { className: dropdownClasses.action, children: [showTopBar && jsx("i", { className: dropdownClasses.actionTopBar }), jsxs("div", { className: dropdownClasses.actionTools, children: [hasCancel && (jsx(Button, { variant: "base-ghost", size: actionButtonSize, onClick: onCancel, children: cancelLabel })), hasConfirm && (jsx(Button, { size: actionButtonSize, style: hasCancel ? undefined : { marginLeft: 'auto' }, onClick: onConfirm, children: confirmLabel })), isCustomMode && (jsx(Button, { size: actionButtonSize, variant: "base-ghost", ...customActionButtonProps, onClick: onClick, children: actionLabel })), isClearMode && (jsx(Button, { size: actionButtonSize, variant: "base-ghost", icon: {
21
- position: 'leading',
22
- src: CloseIcon,
23
- }, onClick: onClear, children: clearLabel }))] })] })) }));
20
+ return (jsx(Fragment, { children: showActions && hasAnyEvent && (jsxs("div", { className: dropdownClasses.action, children: [showTopBar && jsx("i", { className: dropdownClasses.actionTopBar }), jsxs("div", { className: dropdownClasses.actionTools, children: [hasCancel && (jsx(Button, { variant: "base-ghost", size: actionButtonSize, onClick: onCancel, children: cancelLabel })), hasConfirm && (jsx(Button, { size: actionButtonSize, style: hasCancel ? undefined : { marginLeft: 'auto' }, onClick: onConfirm, children: confirmLabel })), isCustomMode && (jsx(Button, { size: actionButtonSize, variant: "base-ghost", ...customActionButtonProps, onClick: onClick, children: actionLabel })), isClearMode && (jsx(Button, { size: actionButtonSize, variant: "base-ghost", iconType: "leading", icon: CloseIcon, onClick: onClear, children: clearLabel }))] })] })) }));
24
21
  }
25
22
 
26
23
  export { DropdownAction as default };
@@ -1,5 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
- import { DropdownItemSharedProps, DropdownOptionsByType, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
2
+ import { DropdownItemSharedProps, DropdownOptionsByType, DropdownStatus as DropdownStatusType, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
3
+ import { type IconDefinition } from '@mezzanine-ui/icons';
3
4
  import { type DropdownActionProps } from './DropdownAction';
4
5
  export interface DropdownItemProps<T extends DropdownType | undefined = DropdownType> extends Omit<DropdownItemSharedProps, 'type'> {
5
6
  /**
@@ -56,5 +57,31 @@ export interface DropdownItemProps<T extends DropdownType | undefined = Dropdown
56
57
  * - 'tree': array with nested children up to 3 levels
57
58
  */
58
59
  type?: DropdownType;
60
+ /**
61
+ * The status of the dropdown (loading or empty).
62
+ */
63
+ status?: DropdownStatusType;
64
+ /**
65
+ * The text of the dropdown loading status.
66
+ */
67
+ loadingText?: string;
68
+ /**
69
+ * The text of the dropdown empty status.
70
+ */
71
+ emptyText?: string;
72
+ /**
73
+ * The icon of the dropdown empty status.
74
+ */
75
+ emptyIcon?: IconDefinition;
76
+ /**
77
+ * Callback fired when the dropdown list reaches the bottom.
78
+ * Only fires when `maxHeight` is set and the list is scrollable.
79
+ */
80
+ onReachBottom?: () => void;
81
+ /**
82
+ * Callback fired when the dropdown list leaves the bottom.
83
+ * Only fires when `maxHeight` is set and the list is scrollable.
84
+ */
85
+ onLeaveBottom?: () => void;
59
86
  }
60
87
  export default function DropdownItem<T extends DropdownType | undefined = DropdownType>(props: DropdownItemProps<T>): import("react/jsx-runtime").JSX.Element;