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

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 (103) hide show
  1. package/AutoComplete/AutoComplete.d.ts +5 -0
  2. package/AutoComplete/AutoComplete.js +19 -2
  3. package/Breadcrumb/BreadcrumbDropdown.js +1 -1
  4. package/Breadcrumb/BreadcrumbItem.js +1 -1
  5. package/Breadcrumb/BreadcrumbOverflowMenuItem.js +1 -1
  6. package/Calendar/Calendar.js +2 -6
  7. package/Calendar/CalendarCell.d.ts +22 -0
  8. package/Calendar/CalendarCell.js +6 -2
  9. package/Calendar/CalendarControls.js +1 -1
  10. package/Calendar/CalendarDayOfWeek.js +3 -2
  11. package/Calendar/CalendarDays.js +5 -1
  12. package/Calendar/CalendarHalfYears.js +13 -7
  13. package/Calendar/CalendarMonths.js +13 -6
  14. package/Calendar/CalendarQuarters.js +13 -7
  15. package/Calendar/CalendarWeeks.js +87 -34
  16. package/Calendar/CalendarYears.js +13 -12
  17. package/Calendar/useCalendarControlModifiers.d.ts +1 -1
  18. package/Calendar/useCalendarControlModifiers.js +12 -12
  19. package/Calendar/useCalendarControls.d.ts +4 -4
  20. package/Calendar/useCalendarControls.js +33 -19
  21. package/Calendar/useRangeCalendarControls.d.ts +8 -8
  22. package/Calendar/useRangeCalendarControls.js +42 -31
  23. package/DateRangePicker/useDateRangeCalendarControls.js +8 -2
  24. package/DateTimePicker/DateTimePicker.js +8 -4
  25. package/DateTimeRangePicker/DateTimeRangePicker.d.ts +34 -0
  26. package/DateTimeRangePicker/DateTimeRangePicker.js +118 -0
  27. package/DateTimeRangePicker/index.d.ts +2 -0
  28. package/DateTimeRangePicker/index.js +1 -0
  29. package/Drawer/Drawer.d.ts +132 -1
  30. package/Drawer/Drawer.js +47 -3
  31. package/Dropdown/Dropdown.d.ts +34 -3
  32. package/Dropdown/Dropdown.js +17 -29
  33. package/Dropdown/DropdownItem.d.ts +32 -0
  34. package/Dropdown/DropdownItem.js +112 -10
  35. package/Dropdown/DropdownItemCard.d.ts +5 -0
  36. package/Dropdown/DropdownItemCard.js +2 -2
  37. package/Form/FormField.d.ts +14 -2
  38. package/Form/FormField.js +3 -3
  39. package/Form/useSelectValueControl.d.ts +3 -4
  40. package/Form/useSelectValueControl.js +51 -39
  41. package/Input/Input.js +3 -19
  42. package/Input/SelectButton/SelectButton.d.ts +25 -4
  43. package/Input/SelectButton/SelectButton.js +21 -9
  44. package/Modal/MediaPreviewModal.d.ts +11 -0
  45. package/Modal/MediaPreviewModal.js +24 -7
  46. package/Modal/Modal.d.ts +1 -1
  47. package/Modal/Modal.js +1 -1
  48. package/Modal/useModalContainer.js +6 -2
  49. package/MultipleDatePicker/MultipleDatePicker.d.ts +62 -0
  50. package/MultipleDatePicker/MultipleDatePicker.js +176 -0
  51. package/MultipleDatePicker/MultipleDatePickerTrigger.d.ts +56 -0
  52. package/MultipleDatePicker/MultipleDatePickerTrigger.js +92 -0
  53. package/MultipleDatePicker/index.d.ts +6 -0
  54. package/MultipleDatePicker/index.js +3 -0
  55. package/MultipleDatePicker/useMultipleDatePickerValue.d.ts +55 -0
  56. package/MultipleDatePicker/useMultipleDatePickerValue.js +68 -0
  57. package/NotificationCenter/NotificationCenterDrawer.d.ts +10 -52
  58. package/NotificationCenter/NotificationCenterDrawer.js +128 -0
  59. package/NotificationCenter/index.d.ts +2 -0
  60. package/NotificationCenter/index.js +1 -0
  61. package/OverflowTooltip/index.d.ts +2 -2
  62. package/Picker/RangePickerTrigger.js +1 -1
  63. package/Popper/Popper.js +2 -1
  64. package/Scrollbar/Scrollbar.js +1 -0
  65. package/Section/Section.d.ts +32 -0
  66. package/Section/Section.js +62 -0
  67. package/Section/index.d.ts +2 -0
  68. package/Select/Select.d.ts +42 -18
  69. package/Select/Select.js +165 -51
  70. package/Select/TreeSelect.d.ts +10 -5
  71. package/Select/TreeSelect.js +12 -5
  72. package/Select/index.d.ts +8 -9
  73. package/Select/index.js +3 -3
  74. package/TimePanel/TimePanelColumn.js +16 -14
  75. package/TimeRangePicker/TimeRangePicker.d.ts +29 -0
  76. package/TimeRangePicker/TimeRangePicker.js +96 -0
  77. package/TimeRangePicker/index.d.ts +3 -0
  78. package/TimeRangePicker/index.js +2 -0
  79. package/TimeRangePicker/useTimeRangePickerValue.d.ts +30 -0
  80. package/TimeRangePicker/useTimeRangePickerValue.js +92 -0
  81. package/Transition/Rotate.js +2 -5
  82. package/Tree/TreeNode.js +2 -2
  83. package/index.d.ts +9 -6
  84. package/index.js +7 -6
  85. package/package.json +4 -4
  86. package/AppBar/AppBar.d.ts +0 -14
  87. package/AppBar/AppBar.js +0 -33
  88. package/AppBar/AppBarBrand.d.ts +0 -4
  89. package/AppBar/AppBarBrand.js +0 -11
  90. package/AppBar/AppBarMain.d.ts +0 -4
  91. package/AppBar/AppBarMain.js +0 -11
  92. package/AppBar/AppBarSupport.d.ts +0 -4
  93. package/AppBar/AppBarSupport.js +0 -11
  94. package/AppBar/index.d.ts +0 -8
  95. package/AppBar/index.js +0 -4
  96. package/Popconfirm/Popconfirm.d.ts +0 -16
  97. package/Popconfirm/Popconfirm.js +0 -15
  98. package/Popconfirm/index.d.ts +0 -2
  99. package/Popconfirm/index.js +0 -1
  100. package/Popover/Popover.d.ts +0 -23
  101. package/Popover/Popover.js +0 -35
  102. package/Popover/index.d.ts +0 -2
  103. package/Popover/index.js +0 -1
package/Drawer/Drawer.js CHANGED
@@ -1,22 +1,66 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { forwardRef, useState } from 'react';
2
+ import { forwardRef, useState, useMemo } from 'react';
3
3
  import { drawerClasses } from '@mezzanine-ui/core/drawer';
4
4
  import { useDocumentEscapeKeyDown } from '../hooks/useDocumentEscapeKeyDown.js';
5
5
  import useTopStack from '../_internal/SlideFadeOverlay/useTopStack.js';
6
6
  import ClearActions from '../ClearActions/ClearActions.js';
7
7
  import Button from '../Button/Button.js';
8
+ import Radio from '../Radio/Radio.js';
9
+ import RadioGroup from '../Radio/RadioGroup.js';
8
10
  import { MOTION_EASING, MOTION_DURATION } from '@mezzanine-ui/system/motion';
9
11
  import Backdrop from '../Backdrop/Backdrop.js';
10
12
  import Slide from '../Transition/Slide.js';
11
13
  import cx from 'clsx';
12
14
 
13
15
  const Drawer = forwardRef((props, ref) => {
14
- const { bottomGhostActionText, bottomOnGhostActionClick, bottomOnPrimaryActionClick, bottomOnSecondaryActionClick, bottomPrimaryActionText, bottomSecondaryActionText, children, className, container, disableCloseOnBackdropClick = false, disableCloseOnEscapeKeyDown = false, disablePortal, headerTitle, isBottomDisplay, isHeaderDisplay, onBackdropClick, onClose, open, size = 'medium', ...rest } = props;
16
+ const { bottomGhostActionDisabled, bottomGhostActionIcon, bottomGhostActionIconType, bottomGhostActionLoading, bottomGhostActionSize, bottomGhostActionText, bottomGhostActionVariant = 'base-ghost', bottomOnGhostActionClick, bottomOnPrimaryActionClick, bottomOnSecondaryActionClick, bottomPrimaryActionDisabled, bottomPrimaryActionIcon, bottomPrimaryActionIconType, bottomPrimaryActionLoading, bottomPrimaryActionSize, bottomPrimaryActionText, bottomPrimaryActionVariant = 'base-primary', bottomSecondaryActionDisabled, bottomSecondaryActionIcon, bottomSecondaryActionIconType, bottomSecondaryActionLoading, bottomSecondaryActionSize, bottomSecondaryActionText, bottomSecondaryActionVariant = 'base-secondary', children, className, container, controlBarAllRadioLabel, controlBarCustomButtonLabel = '全部已讀', controlBarDefaultValue, controlBarIsEmpty = false, controlBarOnCustomButtonClick, controlBarOnRadioChange, controlBarReadRadioLabel, controlBarShow = false, controlBarShowUnreadButton = false, controlBarUnreadRadioLabel, controlBarValue, disableCloseOnBackdropClick = false, disableCloseOnEscapeKeyDown = false, disablePortal, headerTitle, isBottomDisplay, isHeaderDisplay, onBackdropClick, onClose, open, renderControlBar: customRenderControlBar, size = 'medium', ...rest } = props;
15
17
  const [exited, setExited] = useState(true);
16
18
  /**
17
19
  * Escape keydown close: escape will only close the top drawer
18
20
  */
19
21
  const checkIsOnTheTop = useTopStack(open);
22
+ const renderControlBar = useMemo(() => {
23
+ // If custom renderControlBar is provided, use it
24
+ if (customRenderControlBar) {
25
+ return customRenderControlBar;
26
+ }
27
+ // Default control bar implementation
28
+ if (!controlBarShow) {
29
+ return undefined;
30
+ }
31
+ return () => {
32
+ const radios = [];
33
+ if (controlBarAllRadioLabel) {
34
+ radios.push(jsx(Radio, { type: "segment", value: "all", children: controlBarAllRadioLabel }, "all"));
35
+ }
36
+ if (controlBarReadRadioLabel) {
37
+ radios.push(jsx(Radio, { type: "segment", value: "read", children: controlBarReadRadioLabel }, "read"));
38
+ }
39
+ if (controlBarUnreadRadioLabel && controlBarShowUnreadButton) {
40
+ radios.push(jsx(Radio, { type: "segment", value: "unread", children: controlBarUnreadRadioLabel }, "unread"));
41
+ }
42
+ const hasRadios = radios.length > 0;
43
+ const hasButton = controlBarOnCustomButtonClick !== undefined;
44
+ // Don't render if neither radios nor button are provided
45
+ if (!hasRadios && !hasButton) {
46
+ return null;
47
+ }
48
+ return (jsxs("div", { className: cx(drawerClasses.controlBar, !hasRadios && hasButton && drawerClasses.controlBarButtonOnly), children: [hasRadios && (jsx(RadioGroup, { defaultValue: controlBarDefaultValue !== null && controlBarDefaultValue !== void 0 ? controlBarDefaultValue : 'all', onChange: controlBarOnRadioChange, size: "minor", type: "segment", value: controlBarValue, children: radios })), hasButton && (jsx(Button, { disabled: controlBarIsEmpty, onClick: controlBarOnCustomButtonClick, size: "minor", type: "button", variant: "base-ghost", children: controlBarCustomButtonLabel }))] }));
49
+ };
50
+ }, [
51
+ controlBarAllRadioLabel,
52
+ controlBarCustomButtonLabel,
53
+ controlBarDefaultValue,
54
+ controlBarIsEmpty,
55
+ controlBarOnCustomButtonClick,
56
+ controlBarOnRadioChange,
57
+ controlBarReadRadioLabel,
58
+ controlBarShow,
59
+ controlBarShowUnreadButton,
60
+ controlBarUnreadRadioLabel,
61
+ controlBarValue,
62
+ customRenderControlBar,
63
+ ]);
20
64
  useDocumentEscapeKeyDown(() => {
21
65
  if (!open || disableCloseOnEscapeKeyDown || !onClose) {
22
66
  return;
@@ -37,7 +81,7 @@ const Drawer = forwardRef((props, ref) => {
37
81
  }, easing: {
38
82
  enter: MOTION_EASING.entrance,
39
83
  exit: MOTION_EASING.exit,
40
- }, in: open, onEntered: () => setExited(false), onExited: () => setExited(true), ref: ref, children: jsxs("div", { ...rest, className: cx(drawerClasses.host, drawerClasses.right, drawerClasses.size(size), className), children: [isHeaderDisplay && (jsxs("div", { className: drawerClasses.header, children: [headerTitle, jsx(ClearActions, { onClick: onClose })] })), jsx("div", { className: drawerClasses.content, children: children }), isBottomDisplay && (jsxs("div", { className: drawerClasses.bottom, children: [jsx("div", { children: bottomGhostActionText && bottomOnGhostActionClick && (jsx(Button, { onClick: bottomOnGhostActionClick, type: "button", variant: "base-ghost", children: bottomGhostActionText })) }), jsxs("div", { className: drawerClasses['bottom__actions'], children: [bottomSecondaryActionText && bottomOnSecondaryActionClick && (jsx(Button, { onClick: bottomOnSecondaryActionClick, type: "button", variant: "base-secondary", children: bottomSecondaryActionText })), bottomPrimaryActionText && bottomOnPrimaryActionClick && (jsx(Button, { onClick: bottomOnPrimaryActionClick, type: "button", variant: "base-primary", children: bottomPrimaryActionText }))] })] }))] }) }) }));
84
+ }, in: open, onEntered: () => setExited(false), onExited: () => setExited(true), ref: ref, children: jsxs("div", { ...rest, className: cx(drawerClasses.host, drawerClasses.right, drawerClasses.size(size), className), children: [isHeaderDisplay && (jsxs("div", { className: drawerClasses.header, children: [headerTitle, jsx(ClearActions, { onClick: onClose })] })), renderControlBar === null || renderControlBar === void 0 ? void 0 : renderControlBar(), jsx("div", { className: drawerClasses.content, children: children }), isBottomDisplay && (jsxs("div", { className: drawerClasses.bottom, children: [jsx("div", { children: bottomGhostActionText && bottomOnGhostActionClick && (jsx(Button, { disabled: bottomGhostActionDisabled, icon: bottomGhostActionIcon, iconType: bottomGhostActionIconType, loading: bottomGhostActionLoading, onClick: bottomOnGhostActionClick, size: bottomGhostActionSize, type: "button", variant: bottomGhostActionVariant, children: bottomGhostActionText })) }), jsxs("div", { className: drawerClasses['bottom__actions'], children: [bottomSecondaryActionText && bottomOnSecondaryActionClick && (jsx(Button, { disabled: bottomSecondaryActionDisabled, icon: bottomSecondaryActionIcon, iconType: bottomSecondaryActionIconType, loading: bottomSecondaryActionLoading, onClick: bottomOnSecondaryActionClick, size: bottomSecondaryActionSize, type: "button", variant: bottomSecondaryActionVariant, children: bottomSecondaryActionText })), bottomPrimaryActionText && bottomOnPrimaryActionClick && (jsx(Button, { disabled: bottomPrimaryActionDisabled, icon: bottomPrimaryActionIcon, iconType: bottomPrimaryActionIconType, loading: bottomPrimaryActionLoading, onClick: bottomOnPrimaryActionClick, size: bottomPrimaryActionSize, type: "button", variant: bottomPrimaryActionVariant, children: bottomPrimaryActionText }))] })] }))] }) }) }));
41
85
  });
42
86
 
43
87
  export { Drawer as default };
@@ -163,12 +163,12 @@ export interface DropdownProps extends DropdownItemSharedProps {
163
163
  */
164
164
  emptyIcon?: IconDefinition;
165
165
  /**
166
- * Whether to disable portal.
166
+ * Whether to enable portal.
167
167
  * This prop is only relevant when `inputPosition` is set to 'outside'.
168
168
  * Controls whether the dropdown content is rendered within the current hierarchy or portaled to the body.
169
- * @default false
169
+ * @default true
170
170
  */
171
- disablePortal?: boolean;
171
+ globalPortal?: boolean;
172
172
  /**
173
173
  * Callback fired when the dropdown list reaches the bottom.
174
174
  * Only fires when `maxHeight` is set and the list is scrollable.
@@ -179,5 +179,36 @@ export interface DropdownProps extends DropdownItemSharedProps {
179
179
  * Only fires when `maxHeight` is set and the list is scrollable.
180
180
  */
181
181
  onLeaveBottom?: () => void;
182
+ /**
183
+ * Callback fired when the dropdown list is scrolled.
184
+ * Receives the scroll event and computed scroll information.
185
+ */
186
+ onScroll?: (computed: {
187
+ scrollTop: number;
188
+ maxScrollTop: number;
189
+ }, target: HTMLDivElement) => void;
190
+ /**
191
+ * Whether to defer the initialization of OverlayScrollbars.
192
+ * This can improve initial render performance.
193
+ * @default true
194
+ */
195
+ scrollbarDefer?: boolean | object;
196
+ /**
197
+ * Whether to disable the custom scrollbar component.
198
+ * When false (default), Scrollbar component will be used when maxHeight is set.
199
+ * When true, falls back to native div scrolling (backward compatible).
200
+ * @default false
201
+ */
202
+ scrollbarDisabled?: boolean;
203
+ /**
204
+ * The maximum width of the scrollable container.
205
+ * Can be a CSS value string (e.g., '500px', '100%') or a number (treated as pixels).
206
+ */
207
+ scrollbarMaxWidth?: number | string;
208
+ /**
209
+ * Additional options to pass to OverlayScrollbars.
210
+ * @see https://kingsora.github.io/OverlayScrollbars/#!documentation/options
211
+ */
212
+ scrollbarOptions?: import('overlayscrollbars').PartialOptions;
182
213
  }
183
214
  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, autoUpdate } from '@floating-ui/react-dom';
6
+ import { size, offset } 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', 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;
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, globalPortal = true, onReachBottom, onLeaveBottom, onScroll, mode, value, scrollbarDefer, scrollbarDisabled, scrollbarMaxWidth, scrollbarOptions, } = props;
18
18
  const isInline = inputPosition === 'inside';
19
19
  const inputId = useId();
20
20
  const defaultListboxId = `${inputId}-listbox`;
@@ -101,9 +101,7 @@ function Dropdown(props) {
101
101
  if (!customWidth) {
102
102
  return null;
103
103
  }
104
- const widthValue = typeof customWidth === 'number'
105
- ? `${customWidth}px`
106
- : customWidth;
104
+ const widthValue = typeof customWidth === 'number' ? `${customWidth}px` : customWidth;
107
105
  return {
108
106
  name: 'customWidth',
109
107
  fn: ({ elements }) => {
@@ -138,7 +136,9 @@ function Dropdown(props) {
138
136
  fn: ({ elements }) => {
139
137
  const zIndexNum = typeof zIndexValue === 'number'
140
138
  ? zIndexValue
141
- : (typeof zIndexValue === 'string' ? parseInt(zIndexValue, 10) || zIndexValue : 1);
139
+ : typeof zIndexValue === 'string'
140
+ ? parseInt(zIndexValue, 10) || zIndexValue
141
+ : 1;
142
142
  Object.assign(elements.floating.style, {
143
143
  zIndex: zIndexNum,
144
144
  });
@@ -177,28 +177,6 @@ function Dropdown(props) {
177
177
  const anchorRef = useRef(null);
178
178
  const popperRef = useRef(null);
179
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]);
202
180
  // Extract combobox props logic to avoid duplication
203
181
  const getComboboxProps = useMemo(() => {
204
182
  const childWithRef = children;
@@ -231,6 +209,7 @@ function Dropdown(props) {
231
209
  onSelect,
232
210
  onReachBottom,
233
211
  onLeaveBottom,
212
+ onScroll,
234
213
  options,
235
214
  type,
236
215
  status,
@@ -239,6 +218,10 @@ function Dropdown(props) {
239
218
  emptyIcon,
240
219
  mode,
241
220
  value,
221
+ scrollbarDefer,
222
+ scrollbarDisabled,
223
+ scrollbarMaxWidth,
224
+ scrollbarOptions,
242
225
  }), [
243
226
  actionConfig,
244
227
  mergedActiveIndex,
@@ -252,6 +235,7 @@ function Dropdown(props) {
252
235
  onSelect,
253
236
  onReachBottom,
254
237
  onLeaveBottom,
238
+ onScroll,
255
239
  options,
256
240
  type,
257
241
  status,
@@ -260,6 +244,10 @@ function Dropdown(props) {
260
244
  emptyIcon,
261
245
  mode,
262
246
  value,
247
+ scrollbarDefer,
248
+ scrollbarDisabled,
249
+ scrollbarMaxWidth,
250
+ scrollbarOptions,
263
251
  ]);
264
252
  const triggerElement = useMemo(() => {
265
253
  const childWithRef = children;
@@ -353,7 +341,7 @@ function Dropdown(props) {
353
341
  }, [isInline, isOpen, setOpen]);
354
342
  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 },
355
343
  jsx("div", { children: inlineTriggerElement }))), isOpen && (createElement(Translate, { ...translateProps, from: translateFrom, key: "inline-list", in: true },
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: {
344
+ jsx("div", { children: jsx(DropdownItem, { ...baseDropdownItemProps, headerContent: inlineTriggerElement }) })))] })), !isInline && (jsx(Popper, { ref: popperRef, anchor: anchorRef, className: dropdownClasses.popperWithPortal, controllerRef: popperControllerRef, open: isOpen, disablePortal: !globalPortal, options: {
357
345
  placement: popoverPlacement,
358
346
  middleware: [
359
347
  offsetMiddleware,
@@ -1,6 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { DropdownItemSharedProps, DropdownOptionsByType, DropdownStatus as DropdownStatusType, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
3
3
  import { type IconDefinition } from '@mezzanine-ui/icons';
4
+ import type { PartialOptions } from 'overlayscrollbars';
4
5
  import { type DropdownActionProps } from './DropdownAction';
5
6
  export interface DropdownItemProps<T extends DropdownType | undefined = DropdownType> extends Omit<DropdownItemSharedProps, 'type'> {
6
7
  /**
@@ -83,5 +84,36 @@ export interface DropdownItemProps<T extends DropdownType | undefined = Dropdown
83
84
  * Only fires when `maxHeight` is set and the list is scrollable.
84
85
  */
85
86
  onLeaveBottom?: () => void;
87
+ /**
88
+ * Callback fired when the dropdown list is scrolled.
89
+ * Receives the scroll event and computed scroll information.
90
+ */
91
+ onScroll?: (computed: {
92
+ scrollTop: number;
93
+ maxScrollTop: number;
94
+ }, target: HTMLDivElement) => void;
95
+ /**
96
+ * Whether to defer the initialization of OverlayScrollbars.
97
+ * This can improve initial render performance.
98
+ * @default true
99
+ */
100
+ scrollbarDefer?: boolean | object;
101
+ /**
102
+ * Whether to disable the custom scrollbar component.
103
+ * When false (default), Scrollbar component will be used when maxHeight is set.
104
+ * When true, falls back to native div scrolling (backward compatible).
105
+ * @default false
106
+ */
107
+ scrollbarDisabled?: boolean;
108
+ /**
109
+ * The maximum width of the scrollable container.
110
+ * Can be a CSS value string (e.g., '500px', '100%') or a number (treated as pixels).
111
+ */
112
+ scrollbarMaxWidth?: number | string;
113
+ /**
114
+ * Additional options to pass to OverlayScrollbars.
115
+ * @see https://kingsora.github.io/OverlayScrollbars/#!documentation/options
116
+ */
117
+ scrollbarOptions?: PartialOptions;
86
118
  }
87
119
  export default function DropdownItem<T extends DropdownType | undefined = DropdownType>(props: DropdownItemProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -10,7 +10,19 @@ import DropdownAction from './DropdownAction.js';
10
10
  import DropdownItemCard from './DropdownItemCard.js';
11
11
  import DropdownStatus from './DropdownStatus.js';
12
12
  import { shortcutTextHandler } from './shortcutTextHandler.js';
13
+ import Scrollbar from '../Scrollbar/Scrollbar.js';
13
14
 
15
+ // Helper function to recursively get all descendant IDs from a tree option (excluding the option itself)
16
+ function getAllDescendantIds(option) {
17
+ const ids = [];
18
+ if (option.children && option.children.length > 0) {
19
+ option.children.forEach((child) => {
20
+ ids.push(String(child.id));
21
+ ids.push(...getAllDescendantIds(child));
22
+ });
23
+ }
24
+ return ids;
25
+ }
14
26
  /**
15
27
  * Limits DropdownOption array to a maximum depth, truncating extra children levels and showing error message if exceeded.
16
28
  * @param input - The original DropdownOption array
@@ -57,13 +69,16 @@ function truncateArrayDepth(input, maxDepth = 3, warn = true) {
57
69
  return truncate(input);
58
70
  }
59
71
  function DropdownItem(props) {
60
- const { activeIndex, disabled = false, listboxId, listboxLabel, mode = 'single', options, value, type, maxHeight, actionConfig, onHover, onSelect, followText, headerContent, status, loadingText, emptyText, emptyIcon, onReachBottom, onLeaveBottom, } = props;
72
+ const { activeIndex, disabled = false, listboxId, listboxLabel, mode = 'single', options, value, type, maxHeight, actionConfig, onHover, onSelect, followText, headerContent, status, loadingText, emptyText, emptyIcon, onReachBottom, onLeaveBottom, onScroll, scrollbarDefer = true, scrollbarDisabled = false, scrollbarMaxWidth, scrollbarOptions, } = props;
61
73
  const optionsContent = truncateArrayDepth(options, 3);
62
74
  const listRef = useRef(null);
63
75
  const listWrapperRef = useRef(null);
76
+ const viewportRef = useRef(null);
77
+ const wasAtBottomRef = useRef(false);
64
78
  const [expandedNodes, setExpandedNodes] = useState(new Set());
65
79
  const hasActions = Boolean(actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.showActions);
66
80
  const hasHeader = Boolean(headerContent);
81
+ const shouldUseScrollbar = maxHeight && !scrollbarDisabled;
67
82
  // Use custom hook to measure element heights
68
83
  const [actionRef, actionHeight] = useElementHeight(hasActions && !!maxHeight);
69
84
  const [headerRef, headerHeight] = useElementHeight(hasHeader && !!maxHeight);
@@ -200,17 +215,39 @@ function DropdownItem(props) {
200
215
  });
201
216
  return { elements, nextIndex: currentIndex };
202
217
  };
218
+ const calculateNodeSelectionState = useCallback((option, selectedIds) => {
219
+ if (!option.children || option.children.length === 0) {
220
+ const isSelected = selectedIds.includes(String(option.id));
221
+ return { checked: isSelected, indeterminate: false };
222
+ }
223
+ // Get all descendant IDs (excluding the parent node itself)
224
+ const allDescendantIds = getAllDescendantIds(option);
225
+ const selectedDescendants = allDescendantIds.filter((id) => selectedIds.includes(id));
226
+ const totalDescendants = allDescendantIds.length;
227
+ if (totalDescendants === 0) {
228
+ // No descendants, check if parent itself is selected
229
+ const isSelected = selectedIds.includes(String(option.id));
230
+ return { checked: isSelected, indeterminate: false };
231
+ }
232
+ if (selectedDescendants.length === 0) {
233
+ return { checked: false, indeterminate: false };
234
+ }
235
+ if (selectedDescendants.length === totalDescendants) {
236
+ // All descendants are selected
237
+ return { checked: true, indeterminate: false };
238
+ }
239
+ // Some but not all descendants are selected
240
+ return { checked: false, indeterminate: true };
241
+ }, []);
203
242
  const renderTreeOptions = (optionList, depth, startIndex) => {
204
243
  let currentIndex = startIndex;
244
+ const selectedIds = Array.isArray(value) ? value.map((id) => String(id)) : value ? [String(value)] : [];
205
245
  const elements = (optionList !== null && optionList !== void 0 ? optionList : []).flatMap((option) => {
206
246
  var _a, _b, _c;
207
247
  currentIndex += 1;
208
248
  const optionIndex = currentIndex;
209
249
  const level = Math.min(depth, 2);
210
250
  const isActive = optionIndex === activeIndex;
211
- const isSelected = Array.isArray(value)
212
- ? value.includes(option.id)
213
- : value === option.id;
214
251
  const hasChildren = Boolean(option.children && option.children.length > 0);
215
252
  const isExpanded = hasChildren && expandedNodes.has(option.id);
216
253
  let prependIcon = undefined;
@@ -221,13 +258,31 @@ function DropdownItem(props) {
221
258
  const shortcutText = option.shortcutText
222
259
  ? option.shortcutText
223
260
  : shortcutTextHandler((_a = option.shortcutKeys) !== null && _a !== void 0 ? _a : []);
224
- const card = (jsx(DropdownItemCard, { active: isActive, checked: isSelected, disabled: disabled, id: `${listboxId}-option-${optionIndex}`, label: option.name, level: level, mode: mode, name: option.name, onClick: () => {
261
+ const selectionState = hasChildren && mode === 'multiple'
262
+ ? calculateNodeSelectionState(option, selectedIds)
263
+ : {
264
+ checked: selectedIds.includes(String(option.id)),
265
+ indeterminate: false,
266
+ };
267
+ const card = (jsx(DropdownItemCard, { active: isActive, checked: selectionState.checked, indeterminate: selectionState.indeterminate, disabled: disabled, id: `${listboxId}-option-${optionIndex}`, label: option.name, level: level, mode: mode, name: option.name, onClick: () => {
225
268
  if (disabled)
226
269
  return;
227
- if (hasChildren && type === 'tree') {
270
+ if (hasChildren && type === 'tree' && mode === 'multiple' && option.showCheckbox) {
271
+ toggleExpand(option.id);
272
+ }
273
+ else if (hasChildren && type === 'tree') {
228
274
  toggleExpand(option.id);
229
275
  }
230
276
  else {
277
+ // In `tree` + `multiple` mode, `DropdownItemCard` already triggers selection via
278
+ // `onCheckedChange` when row is clicked (it toggles checked first, then calls `onClick`),
279
+ // so calling `onSelect` here would cause it to fire twice for leaf nodes.
280
+ if (!(type === 'tree' && mode === 'multiple')) {
281
+ onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
282
+ }
283
+ }
284
+ }, onCheckedChange: () => {
285
+ if (!disabled) {
231
286
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
232
287
  }
233
288
  }, followText: followText, checkSite: checkSite, onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(optionIndex), prependIcon: prependIcon, showUnderline: (_b = option.showUnderline) !== null && _b !== void 0 ? _b : false, validate: (_c = option.validate) !== null && _c !== void 0 ? _c : 'default', appendContent: shortcutText }, option.id));
@@ -292,6 +347,10 @@ function DropdownItem(props) {
292
347
  maxHeight: `${availableHeight}px`,
293
348
  };
294
349
  }, [maxHeight, actionHeight, headerHeight]);
350
+ const getIsAtBottom = useCallback((viewport) => {
351
+ const { scrollTop, scrollHeight, clientHeight } = viewport;
352
+ return scrollTop + clientHeight >= scrollHeight - 1;
353
+ }, []);
295
354
  useEffect(() => {
296
355
  const listElement = listRef.current;
297
356
  if (!listElement || disabled) {
@@ -321,10 +380,17 @@ function DropdownItem(props) {
321
380
  listElement.removeEventListener('keydown', handleKeyDown);
322
381
  };
323
382
  }, [disabled, matchShortcut, onSelect, type, toggleExpand, visibleShortcutOptions]);
324
- // Handle scroll to bottom detection
383
+ const handleViewportReady = useCallback((viewport) => {
384
+ viewportRef.current = viewport;
385
+ listWrapperRef.current = viewport;
386
+ wasAtBottomRef.current = getIsAtBottom(viewport);
387
+ }, [getIsAtBottom]);
325
388
  useEffect(() => {
389
+ if (shouldUseScrollbar) {
390
+ return;
391
+ }
326
392
  const listWrapperElement = listWrapperRef.current;
327
- if (!listWrapperElement || !maxHeight || (!onReachBottom && !onLeaveBottom)) {
393
+ if (!listWrapperElement || !maxHeight || (!onReachBottom && !onLeaveBottom && !onScroll)) {
328
394
  return;
329
395
  }
330
396
  // Initialize wasAtBottom state by checking current position
@@ -335,6 +401,14 @@ function DropdownItem(props) {
335
401
  let wasAtBottom = checkInitialState();
336
402
  const handleScroll = () => {
337
403
  const { scrollTop, scrollHeight, clientHeight } = listWrapperElement;
404
+ const maxScrollTop = scrollHeight - clientHeight;
405
+ // Call onScroll callback if provided
406
+ if (onScroll) {
407
+ onScroll({
408
+ scrollTop,
409
+ maxScrollTop,
410
+ }, listWrapperElement);
411
+ }
338
412
  // Check if scrolled to bottom (with 1px threshold for rounding errors)
339
413
  const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1;
340
414
  // Trigger onReachBottom when entering bottom state
@@ -351,9 +425,37 @@ function DropdownItem(props) {
351
425
  return () => {
352
426
  listWrapperElement.removeEventListener('scroll', handleScroll);
353
427
  };
354
- }, [maxHeight, onReachBottom, onLeaveBottom]);
428
+ }, [maxHeight, onReachBottom, onLeaveBottom, onScroll, shouldUseScrollbar]);
429
+ const scrollbarEvents = useMemo(() => {
430
+ if (!shouldUseScrollbar || (!onReachBottom && !onLeaveBottom && !onScroll)) {
431
+ return undefined;
432
+ }
433
+ return {
434
+ scroll: (_instance, _event) => {
435
+ const viewport = viewportRef.current;
436
+ if (!viewport)
437
+ return;
438
+ const { scrollTop, scrollHeight, clientHeight } = viewport;
439
+ const maxScrollTop = scrollHeight - clientHeight;
440
+ if (onScroll) {
441
+ onScroll({
442
+ scrollTop,
443
+ maxScrollTop,
444
+ }, viewport);
445
+ }
446
+ const isAtBottom = getIsAtBottom(viewport);
447
+ if (isAtBottom && !wasAtBottomRef.current) {
448
+ onReachBottom === null || onReachBottom === void 0 ? void 0 : onReachBottom();
449
+ }
450
+ if (!isAtBottom && wasAtBottomRef.current) {
451
+ onLeaveBottom === null || onLeaveBottom === void 0 ? void 0 : onLeaveBottom();
452
+ }
453
+ wasAtBottomRef.current = isAtBottom;
454
+ },
455
+ };
456
+ }, [getIsAtBottom, shouldUseScrollbar, onReachBottom, onLeaveBottom, onScroll]);
355
457
  return (jsxs("ul", { "aria-label": listboxLabel || (optionsContent.length === 0 ? 'Dropdown options' : undefined), className: dropdownClasses.list, id: listboxId, ref: listRef, role: "listbox", style: listStyle, tabIndex: -1, children: [hasHeader && (jsx("li", { className: dropdownClasses.listHeader, role: "presentation", ref: headerRef, children: jsx("div", { className: dropdownClasses.listHeaderInner, children: headerContent }) })), maxHeight
356
- ? (jsx("div", { ref: listWrapperRef, className: dropdownClasses.listWrapper, style: listWrapperStyle, children: shouldShowStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (renderedOptions) }))
458
+ ? (shouldUseScrollbar ? (jsx(Scrollbar, { className: dropdownClasses.listWrapper, defer: scrollbarDefer, disabled: false, events: scrollbarEvents, maxHeight: listWrapperStyle === null || listWrapperStyle === void 0 ? void 0 : listWrapperStyle.maxHeight, maxWidth: scrollbarMaxWidth, onViewportReady: handleViewportReady, options: scrollbarOptions, children: shouldShowStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (renderedOptions) })) : (jsx("div", { ref: listWrapperRef, className: dropdownClasses.listWrapper, style: listWrapperStyle, children: shouldShowStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (renderedOptions) })))
357
459
  : shouldShowStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (renderedOptions), hasActions && (jsx("div", { ref: actionRef, children: jsx(DropdownAction, { ...actionConfig }) }))] }));
358
460
  }
359
461
 
@@ -25,6 +25,11 @@ export interface DropdownItemCardProps {
25
25
  * When provided, the state is controlled externally.
26
26
  */
27
27
  checked?: boolean;
28
+ /**
29
+ * Whether the checkbox is in indeterminate state.
30
+ * Used in tree mode when some but not all children are selected.
31
+ */
32
+ indeterminate?: boolean;
28
33
  /**
29
34
  * Additional className for the list item.
30
35
  */
@@ -10,7 +10,7 @@ import Icon from '../Icon/Icon.js';
10
10
  import Checkbox from '../Checkbox/Checkbox.js';
11
11
 
12
12
  function DropdownItemCard(props) {
13
- const { active = false, appendIcon, appendContent, followText, id, label, level: levelProp, mode, name: _name, prependIcon, subTitle, validate, disabled, checked, defaultChecked, checkSite, onCheckedChange, onClick, className, onMouseEnter, showUnderline, } = props;
13
+ const { active = false, appendIcon, appendContent, followText, id, label, level: levelProp, mode, name: _name, prependIcon, subTitle, validate, disabled, checked, defaultChecked, indeterminate = false, checkSite, onCheckedChange, onClick, className, onMouseEnter, showUnderline, } = props;
14
14
  const cardLabel = label || '';
15
15
  const cardName = _name || cardLabel;
16
16
  const level = levelProp || 0;
@@ -111,7 +111,7 @@ function DropdownItemCard(props) {
111
111
  [dropdownClasses.cardActive]: active || isChecked,
112
112
  [dropdownClasses.cardDisabled]: disabled,
113
113
  [dropdownClasses.cardDanger]: validate === 'danger',
114
- }, className), id: id, role: "option", tabIndex: -1, onMouseEnter: onMouseEnter, onClick: handleClick, onKeyDown: handleKeyDown, children: jsxs("div", { className: dropdownClasses.cardContainer, children: [showPrependContent && (jsxs("div", { className: dropdownClasses.cardPrependContent, children: [prependIcon && jsx(Icon, { icon: prependIcon, color: iconColor }), checkSite === 'prefix' && mode === 'multiple' && (jsx(Checkbox, { checked: isChecked, disabled: disabled, onChange: handleCheckboxChange }))] })), jsxs("div", { className: dropdownClasses.cardBody, children: [cardLabel &&
114
+ }, className), id: id, role: "option", tabIndex: -1, onMouseEnter: onMouseEnter, onClick: handleClick, onKeyDown: handleKeyDown, children: jsxs("div", { className: dropdownClasses.cardContainer, children: [showPrependContent && (jsxs("div", { className: dropdownClasses.cardPrependContent, children: [prependIcon && jsx(Icon, { icon: prependIcon, color: iconColor }), checkSite === 'prefix' && mode === 'multiple' && (jsx(Checkbox, { checked: isChecked, disabled: disabled, indeterminate: indeterminate, onChange: handleCheckboxChange }))] })), jsxs("div", { className: dropdownClasses.cardBody, children: [cardLabel &&
115
115
  renderHighlightedText(labelParts, dropdownClasses.cardTitle, labelId), subTitleParts.length > 0 &&
116
116
  renderHighlightedText(subTitleParts, dropdownClasses.cardDescription)] }), showAppendContent && (jsxs("div", { className: dropdownClasses.cardAppendContent, children: [appendContent && (jsx(Typography, { color: "text-neutral-light", children: appendContent })), appendIcon && jsx(Icon, { icon: appendIcon, color: iconColor }), checkSite === 'suffix' && isChecked && (jsx(Icon, { icon: CheckedIcon, color: appendIconColor, size: 16 }))] }))] }) }), showUnderline && jsx("div", { className: dropdownClasses.cardUnderline })] }));
117
117
  }
@@ -1,4 +1,4 @@
1
- import { FormFieldCounterColor, FormFieldSize } from '@mezzanine-ui/core/form';
1
+ import { ControlFieldSlotLayout, FormFieldCounterColor, FormFieldSize, LabelLayout } from '@mezzanine-ui/core/form';
2
2
  import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
3
3
  import { IconDefinition } from '@mezzanine-ui/icons';
4
4
  import { SeverityWithInfo } from '@mezzanine-ui/system/severity';
@@ -13,6 +13,12 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
13
13
  * @default FormFieldCounterColor.INFO
14
14
  */
15
15
  counterColor?: FormFieldCounterColor;
16
+ /**
17
+ * The layout variant for the control field slot.
18
+ * Controls the visual styling and appearance of the input control area.
19
+ * @default ControlFieldSlotLayout.MAIN
20
+ */
21
+ controlFieldSlotLayout?: ControlFieldSlotLayout;
16
22
  /**
17
23
  * To control the field passed from children whether should be disabled.
18
24
  * The form message won't appear if disabled.
@@ -34,7 +40,7 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
34
40
  /**
35
41
  * The label text for the form field.
36
42
  */
37
- label: string;
43
+ label?: string;
38
44
  /**
39
45
  * The icon to display next to the label.
40
46
  * When provided, displays an icon that shows a tooltip on hover.
@@ -50,6 +56,12 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
50
56
  * Typically used to show "(optional)" or similar text.
51
57
  */
52
58
  labelOptionalMarker?: string;
59
+ /**
60
+ * The layout variant for the label area.
61
+ * Controls the visual styling and appearance of the label.
62
+ * @default LabelLayout.HORIZONTAL_MAIN
63
+ */
64
+ labelLayout?: LabelLayout;
53
65
  /**
54
66
  * The name attribute for the form field.
55
67
  * Used to identify the field in form submissions and as htmlFor in the label.
package/Form/FormField.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { forwardRef } from 'react';
3
- import { formFieldClasses, FormFieldCounterColor } from '@mezzanine-ui/core/form';
3
+ import { ControlFieldSlotLayout, LabelLayout, formFieldClasses, FormFieldCounterColor } from '@mezzanine-ui/core/form';
4
4
  import { FormControlContext } from './FormControlContext.js';
5
5
  import FormHintText from './FormHintText.js';
6
6
  import FormLabel from './FormLabel.js';
@@ -10,7 +10,7 @@ import cx from 'clsx';
10
10
  * The React component for `mezzanine` form field.
11
11
  */
12
12
  const FormField = forwardRef(function FormField(props, ref) {
13
- const { children, className, counter, counterColor, disabled = false, fullWidth = false, hintText, hintTextIcon, label, labelInformationIcon, labelInformationText, labelOptionalMarker, name, required = false, size, severity = 'info', ...rest } = props;
13
+ const { children, className, counter, counterColor, controlFieldSlotLayout = ControlFieldSlotLayout.MAIN, disabled = false, fullWidth = false, hintText, hintTextIcon, label, labelInformationIcon, labelInformationText, labelOptionalMarker, labelLayout = LabelLayout.HORIZONTAL_MAIN, name, required = false, size, severity = 'info', ...rest } = props;
14
14
  const formControl = {
15
15
  disabled,
16
16
  fullWidth,
@@ -20,7 +20,7 @@ const FormField = forwardRef(function FormField(props, ref) {
20
20
  return (jsx("div", { ...rest, ref: ref, className: cx(formFieldClasses.host, formFieldClasses.size(size), {
21
21
  [formFieldClasses.disabled]: disabled,
22
22
  [formFieldClasses.fullWidth]: fullWidth,
23
- }, className), children: jsxs(FormControlContext.Provider, { value: formControl, children: [jsx(FormLabel, { className: formFieldClasses.labelArea, htmlFor: name, informationIcon: labelInformationIcon, informationText: labelInformationText, labelText: label, optionalMarker: labelOptionalMarker }), jsxs("div", { className: cx(formFieldClasses.dataEntry), children: [children, hintText || hintTextIcon || counter ? (jsxs("div", { className: cx(formFieldClasses.hintTextAndCounterArea, {
23
+ }, className), children: jsxs(FormControlContext.Provider, { value: formControl, children: [label && (jsx(FormLabel, { className: cx(formFieldClasses.labelArea, `${formFieldClasses.labelArea}--${labelLayout}`), htmlFor: name, informationIcon: labelInformationIcon, informationText: labelInformationText, labelText: label, optionalMarker: labelOptionalMarker })), jsxs("div", { className: cx(formFieldClasses.dataEntry), children: [jsx("div", { className: cx(`${formFieldClasses.controlFieldSlot}--${controlFieldSlotLayout}`), children: children }), hintText || hintTextIcon || counter ? (jsxs("div", { className: cx(formFieldClasses.hintTextAndCounterArea, {
24
24
  [formFieldClasses.hintTextAndCounterArea + '--align-right']: !(hintText || hintTextIcon) && counter,
25
25
  }), children: [(hintText || hintTextIcon) && (jsx(FormHintText, { hintText: hintText, hintTextIcon: hintTextIcon, severity: severity })), counter && (jsx("span", { className: cx(formFieldClasses.counter, formFieldClasses.counterColor(counterColor || FormFieldCounterColor.INFO)), children: counter }))] })) : null] })] }) }));
26
26
  });
@@ -2,19 +2,18 @@ import { MouseEvent } from 'react';
2
2
  import { SelectValue } from '../Select/typings';
3
3
  export interface UseSelectBaseValueControl {
4
4
  onClear?(e: MouseEvent<Element>): void;
5
- onChange?(newOptions: SelectValue[] | SelectValue): any;
6
5
  onClose?(): void;
7
6
  }
8
7
  export type UseSelectMultipleValueControl = UseSelectBaseValueControl & {
9
8
  defaultValue?: SelectValue[];
10
9
  mode: 'multiple';
11
- onChange?(newOptions: SelectValue[]): any;
10
+ onChange?(newOptions: SelectValue[]): void;
12
11
  value?: SelectValue[];
13
12
  };
14
13
  export type UseSelectSingleValueControl = UseSelectBaseValueControl & {
15
14
  defaultValue?: SelectValue;
16
15
  mode: 'single';
17
- onChange?(newOption: SelectValue): any;
16
+ onChange?(newOption: SelectValue | null): void;
18
17
  value?: SelectValue | null;
19
18
  };
20
19
  export type UseSelectValueControl = UseSelectMultipleValueControl | UseSelectSingleValueControl;
@@ -22,7 +21,7 @@ export interface SelectBaseValueControl {
22
21
  onClear(e: MouseEvent<Element>): void;
23
22
  }
24
23
  export type SelectMultipleValueControl = SelectBaseValueControl & {
25
- onChange: (v: SelectValue | null) => SelectValue[];
24
+ onChange: (v: SelectValue | SelectValue[] | null) => SelectValue[];
26
25
  value: SelectValue[];
27
26
  };
28
27
  export type SelectSingleValueControl = SelectBaseValueControl & {