@mezzanine-ui/react 1.0.0-beta.6 → 1.0.0-beta.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 (142) hide show
  1. package/Accordion/Accordion.d.ts +23 -1
  2. package/Accordion/Accordion.js +59 -11
  3. package/Accordion/AccordionActions.d.ts +13 -0
  4. package/Accordion/AccordionActions.js +24 -0
  5. package/Accordion/AccordionContent.d.ts +9 -0
  6. package/Accordion/{AccordionDetails.js → AccordionContent.js} +4 -6
  7. package/Accordion/AccordionControlContext.d.ts +2 -2
  8. package/Accordion/AccordionGroup.d.ts +10 -0
  9. package/Accordion/AccordionGroup.js +26 -0
  10. package/Accordion/AccordionTitle.d.ts +14 -0
  11. package/Accordion/AccordionTitle.js +56 -0
  12. package/Accordion/index.d.ts +8 -4
  13. package/Accordion/index.js +4 -2
  14. package/AutoComplete/AutoComplete.d.ts +20 -6
  15. package/AutoComplete/AutoComplete.js +118 -30
  16. package/Backdrop/Backdrop.js +15 -19
  17. package/Calendar/CalendarDays.js +1 -1
  18. package/Card/BaseCard.d.ts +11 -0
  19. package/Card/BaseCard.js +48 -0
  20. package/Card/BaseCardSkeleton.d.ts +14 -0
  21. package/Card/BaseCardSkeleton.js +18 -0
  22. package/Card/CardGroup.d.ts +47 -0
  23. package/Card/CardGroup.js +147 -0
  24. package/Card/FourThumbnailCard.d.ts +14 -0
  25. package/Card/FourThumbnailCard.js +73 -0
  26. package/Card/FourThumbnailCardSkeleton.d.ts +14 -0
  27. package/Card/FourThumbnailCardSkeleton.js +20 -0
  28. package/Card/QuickActionCard.d.ts +12 -0
  29. package/Card/QuickActionCard.js +23 -0
  30. package/Card/QuickActionCardSkeleton.d.ts +14 -0
  31. package/Card/QuickActionCardSkeleton.js +18 -0
  32. package/Card/SingleThumbnailCard.d.ts +13 -0
  33. package/Card/SingleThumbnailCard.js +44 -0
  34. package/Card/SingleThumbnailCardSkeleton.d.ts +19 -0
  35. package/Card/SingleThumbnailCardSkeleton.js +18 -0
  36. package/Card/Thumbnail.d.ts +12 -0
  37. package/Card/Thumbnail.js +18 -0
  38. package/Card/ThumbnailCardInfo.d.ts +34 -0
  39. package/Card/ThumbnailCardInfo.js +43 -0
  40. package/Card/index.d.ts +43 -4
  41. package/Card/index.js +19 -2
  42. package/Card/typings.d.ts +442 -0
  43. package/Checkbox/Checkbox.d.ts +8 -0
  44. package/Checkbox/Checkbox.js +3 -2
  45. package/Checkbox/CheckboxGroup.js +1 -1
  46. package/ContentHeader/ContentHeader.d.ts +22 -70
  47. package/ContentHeader/ContentHeader.js +1 -1
  48. package/ContentHeader/ContentHeaderResponsive.d.ts +9 -0
  49. package/ContentHeader/ContentHeaderResponsive.js +7 -0
  50. package/ContentHeader/utils.d.ts +3 -3
  51. package/ContentHeader/utils.js +66 -20
  52. package/Cropper/Cropper.d.ts +66 -0
  53. package/Cropper/Cropper.js +115 -0
  54. package/Cropper/CropperElement.d.ts +10 -0
  55. package/Cropper/CropperElement.js +892 -0
  56. package/Cropper/index.d.ts +18 -0
  57. package/Cropper/index.js +8 -0
  58. package/Cropper/tools.d.ts +90 -0
  59. package/Cropper/tools.js +143 -0
  60. package/Cropper/typings.d.ts +69 -0
  61. package/Cropper/utils/cropper-calculations.d.ts +39 -0
  62. package/Cropper/utils/cropper-calculations.js +95 -0
  63. package/DateTimePicker/DateTimePicker.d.ts +1 -1
  64. package/DateTimePicker/DateTimePicker.js +14 -1
  65. package/Dropdown/Dropdown.d.ts +7 -1
  66. package/Dropdown/Dropdown.js +31 -14
  67. package/Dropdown/DropdownItem.d.ts +7 -1
  68. package/Dropdown/DropdownItem.js +36 -6
  69. package/Dropdown/DropdownItemCard.js +2 -1
  70. package/FloatingButton/FloatingButton.d.ts +21 -0
  71. package/FloatingButton/FloatingButton.js +18 -0
  72. package/FloatingButton/index.d.ts +2 -0
  73. package/FloatingButton/index.js +1 -0
  74. package/Form/FormField.d.ts +21 -10
  75. package/Form/FormField.js +12 -4
  76. package/Input/Input.js +9 -2
  77. package/Message/Message.js +1 -1
  78. package/MultipleDatePicker/MultipleDatePicker.js +2 -2
  79. package/Navigation/NavigationHeader.js +1 -1
  80. package/Picker/FormattedInput.d.ts +1 -1
  81. package/Picker/FormattedInput.js +2 -1
  82. package/Picker/PickerTriggerWithSeparator.d.ts +10 -0
  83. package/Picker/PickerTriggerWithSeparator.js +2 -2
  84. package/Picker/useDateInputFormatter.d.ts +6 -0
  85. package/Picker/useDateInputFormatter.js +4 -1
  86. package/Select/Select.d.ts +2 -8
  87. package/Select/Select.js +12 -33
  88. package/Select/SelectTrigger.js +21 -7
  89. package/Select/index.d.ts +0 -4
  90. package/Select/index.js +0 -2
  91. package/Select/typings.d.ts +0 -4
  92. package/Select/useSelectTriggerTags.d.ts +1 -1
  93. package/Select/useSelectTriggerTags.js +9 -6
  94. package/Separator/Separator.d.ts +14 -0
  95. package/Separator/Separator.js +17 -0
  96. package/Separator/index.d.ts +2 -0
  97. package/Separator/index.js +1 -0
  98. package/Table/utils/useTableRowSelection.js +6 -0
  99. package/Tag/TagGroup.d.ts +4 -2
  100. package/Tag/TagGroup.js +7 -4
  101. package/TextField/TextField.d.ts +1 -1
  102. package/TextField/TextField.js +63 -9
  103. package/TimePanel/TimePanelColumn.js +19 -12
  104. package/index.d.ts +27 -28
  105. package/index.js +23 -25
  106. package/package.json +4 -4
  107. package/Accordion/AccordionDetails.d.ts +0 -9
  108. package/Accordion/AccordionSummary.d.ts +0 -18
  109. package/Accordion/AccordionSummary.js +0 -51
  110. package/Alert/Alert.d.ts +0 -20
  111. package/Alert/Alert.js +0 -18
  112. package/Alert/index.d.ts +0 -3
  113. package/Alert/index.js +0 -1
  114. package/Card/Card.d.ts +0 -51
  115. package/Card/Card.js +0 -20
  116. package/Card/CardActions.d.ts +0 -34
  117. package/Card/CardActions.js +0 -15
  118. package/ConfirmActions/ConfirmActions.d.ts +0 -46
  119. package/ConfirmActions/ConfirmActions.js +0 -15
  120. package/ConfirmActions/index.d.ts +0 -2
  121. package/ConfirmActions/index.js +0 -1
  122. package/Select/Option.d.ts +0 -18
  123. package/Select/Option.js +0 -45
  124. package/Select/TreeSelect.d.ts +0 -72
  125. package/Select/TreeSelect.js +0 -205
  126. package/Tree/Tree.d.ts +0 -70
  127. package/Tree/Tree.js +0 -139
  128. package/Tree/TreeNode.d.ts +0 -40
  129. package/Tree/TreeNode.js +0 -50
  130. package/Tree/TreeNodeList.d.ts +0 -24
  131. package/Tree/TreeNodeList.js +0 -28
  132. package/Tree/getTreeNodeEntities.d.ts +0 -11
  133. package/Tree/getTreeNodeEntities.js +0 -92
  134. package/Tree/index.d.ts +0 -13
  135. package/Tree/index.js +0 -7
  136. package/Tree/toggleValue.d.ts +0 -4
  137. package/Tree/toggleValue.js +0 -19
  138. package/Tree/traverseTree.d.ts +0 -2
  139. package/Tree/traverseTree.js +0 -11
  140. package/Tree/typings.d.ts +0 -16
  141. package/Tree/useTreeExpandedValue.d.ts +0 -14
  142. package/Tree/useTreeExpandedValue.js +0 -33
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import keycode from 'keycode';
4
4
  import { useRef, useState, useCallback, useMemo, useEffect } from 'react';
5
5
  import { dropdownClasses } from '@mezzanine-ui/core/dropdown/dropdown';
@@ -69,7 +69,7 @@ function truncateArrayDepth(input, maxDepth = 3, warn = true) {
69
69
  return truncate(input);
70
70
  }
71
71
  function DropdownItem(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;
72
+ const { activeIndex, disabled = false, listboxId, listboxLabel, mode = 'single', options, value, type, maxHeight, actionConfig, onHover, onSelect, followText, headerContent, status, loadingText, emptyText, emptyIcon, loadingPosition = 'full', onReachBottom, onLeaveBottom, onScroll, scrollbarDefer = true, scrollbarDisabled = false, scrollbarMaxWidth, scrollbarOptions, } = props;
73
73
  const optionsContent = truncateArrayDepth(options, 3);
74
74
  const listRef = useRef(null);
75
75
  const listWrapperRef = useRef(null);
@@ -327,8 +327,10 @@ function DropdownItem(props) {
327
327
  return renderDefaultOptions(optionList, startIndex);
328
328
  };
329
329
  const { elements: renderedOptions } = renderOptions(optionsContent, 0, -1);
330
- // Show status when options are empty and status is provided
331
- const shouldShowStatus = optionsContent.length === 0 && status;
330
+ // Show full status when options are empty and status is provided, but not when loadingPosition is 'bottom'
331
+ const shouldShowFullStatus = optionsContent.length === 0 && status && loadingPosition !== 'bottom';
332
+ // Show bottom loading when status is loading and loadingPosition is bottom
333
+ const shouldShowBottomLoading = status === 'loading' && loadingPosition === 'bottom';
332
334
  const listStyle = useMemo(() => {
333
335
  if (!maxHeight) {
334
336
  return undefined;
@@ -385,6 +387,34 @@ function DropdownItem(props) {
385
387
  listWrapperRef.current = viewport;
386
388
  wasAtBottomRef.current = getIsAtBottom(viewport);
387
389
  }, [getIsAtBottom]);
390
+ // Track previous loading state to only scroll when loading appears (not when it disappears)
391
+ const prevShouldShowBottomLoadingRef = useRef(false);
392
+ // Auto-scroll to bottom when bottom loading appears and user was at bottom
393
+ useEffect(() => {
394
+ // Only scroll when loading appears (transitions from false to true)
395
+ const loadingJustAppeared = shouldShowBottomLoading && !prevShouldShowBottomLoadingRef.current;
396
+ prevShouldShowBottomLoadingRef.current = shouldShowBottomLoading;
397
+ if (!loadingJustAppeared)
398
+ return;
399
+ const scrollToBottom = (element) => {
400
+ // Use requestAnimationFrame to ensure DOM is updated after loading element is rendered
401
+ requestAnimationFrame(() => {
402
+ element.scrollTop = element.scrollHeight;
403
+ });
404
+ };
405
+ if (shouldUseScrollbar) {
406
+ const viewport = viewportRef.current;
407
+ if (viewport && wasAtBottomRef.current) {
408
+ scrollToBottom(viewport);
409
+ }
410
+ }
411
+ else {
412
+ const listWrapperElement = listWrapperRef.current;
413
+ if (listWrapperElement && maxHeight && wasAtBottomRef.current) {
414
+ scrollToBottom(listWrapperElement);
415
+ }
416
+ }
417
+ }, [shouldShowBottomLoading, shouldUseScrollbar, maxHeight]);
388
418
  useEffect(() => {
389
419
  if (shouldUseScrollbar) {
390
420
  return;
@@ -455,8 +485,8 @@ function DropdownItem(props) {
455
485
  };
456
486
  }, [getIsAtBottom, shouldUseScrollbar, onReachBottom, onLeaveBottom, onScroll]);
457
487
  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
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) })))
459
- : shouldShowStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (renderedOptions), hasActions && (jsx("div", { ref: actionRef, children: jsx(DropdownAction, { ...actionConfig }) }))] }));
488
+ ? (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: shouldShowFullStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (jsxs(Fragment, { children: [renderedOptions, shouldShowBottomLoading && (jsx("li", { className: dropdownClasses.loadingMore, "aria-live": "polite", role: "status", children: jsx(DropdownStatus, { status: "loading", loadingText: loadingText }) }))] })) })) : (jsx("div", { ref: listWrapperRef, className: dropdownClasses.listWrapper, style: listWrapperStyle, children: shouldShowFullStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (jsxs(Fragment, { children: [renderedOptions, shouldShowBottomLoading && (jsx("li", { className: dropdownClasses.loadingMore, "aria-live": "polite", role: "status", children: jsx(DropdownStatus, { status: "loading", loadingText: loadingText }) }))] })) })))
489
+ : shouldShowFullStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (jsxs(Fragment, { children: [renderedOptions, shouldShowBottomLoading && (jsx("li", { className: dropdownClasses.loadingMore, "aria-live": "polite", role: "status", children: jsx(DropdownStatus, { status: "loading", loadingText: loadingText }) }))] })), hasActions && (jsx("div", { ref: actionRef, children: jsx(DropdownAction, { ...actionConfig }) }))] }));
460
490
  }
461
491
 
462
492
  export { DropdownItem as default };
@@ -8,6 +8,7 @@ import Typography from '../Typography/Typography.js';
8
8
  import { highlightText } from './highlightText.js';
9
9
  import Icon from '../Icon/Icon.js';
10
10
  import Checkbox from '../Checkbox/Checkbox.js';
11
+ import Separator from '../Separator/Separator.js';
11
12
 
12
13
  function DropdownItemCard(props) {
13
14
  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;
@@ -113,7 +114,7 @@ function DropdownItemCard(props) {
113
114
  [dropdownClasses.cardDanger]: validate === 'danger',
114
115
  }, 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
116
  renderHighlightedText(labelParts, dropdownClasses.cardTitle, labelId), subTitleParts.length > 0 &&
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
+ 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("li", { role: "presentation", "aria-hidden": "true", children: jsx(Separator, { orientation: "horizontal", className: dropdownClasses.cardUnderline }) }))] }));
117
118
  }
118
119
 
119
120
  export { DropdownItemCard as default };
@@ -0,0 +1,21 @@
1
+ import { ButtonProps } from '../Button';
2
+ export interface FloatingButtonProps extends Omit<ButtonProps, 'variant' | 'size' | 'className' | 'tooltipPosition'> {
3
+ /**
4
+ * Auto hide floating button when `open` is true.
5
+ * @default false
6
+ */
7
+ autoHideWhenOpen?: boolean;
8
+ /**
9
+ * The class name of the root element.
10
+ */
11
+ className?: string;
12
+ /**
13
+ * Whether the floating button is in open state.
14
+ */
15
+ open?: boolean;
16
+ }
17
+ /**
18
+ * The react component for `mezzanine` floating button.
19
+ */
20
+ declare const FloatingButton: import("react").ForwardRefExoticComponent<FloatingButtonProps & import("react").RefAttributes<HTMLDivElement>>;
21
+ export default FloatingButton;
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { forwardRef } from 'react';
4
+ import Button from '../Button/Button.js';
5
+ import { floatingButtonClasses } from '@mezzanine-ui/core/floating-button';
6
+ import cx from 'clsx';
7
+
8
+ /**
9
+ * The react component for `mezzanine` floating button.
10
+ */
11
+ const FloatingButton = forwardRef(function FloatingButton(props, ref) {
12
+ const { autoHideWhenOpen = false, children, className, open = false, ...rest } = props;
13
+ return (jsx("div", { ref: ref, className: cx(floatingButtonClasses.host, className), children: jsx(Button, { ...rest, className: cx(floatingButtonClasses.button, {
14
+ [floatingButtonClasses.buttonHidden]: autoHideWhenOpen && open,
15
+ }), variant: "base-primary", size: "main", tooltipPosition: "left", children: children }) }));
16
+ });
17
+
18
+ export { FloatingButton as default };
@@ -0,0 +1,2 @@
1
+ export { default } from './FloatingButton';
2
+ export type { FloatingButtonProps } from './FloatingButton';
@@ -0,0 +1 @@
1
+ export { default } from './FloatingButton.js';
@@ -1,4 +1,4 @@
1
- import { ControlFieldSlotLayout, FormFieldCounterColor, FormFieldSize, LabelLayout } from '@mezzanine-ui/core/form';
1
+ import { ControlFieldSlotLayout, FormFieldCounterColor, FormFieldDensity, FormFieldLabelSpacing, FormFieldLayout } 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';
@@ -57,11 +57,27 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
57
57
  */
58
58
  labelOptionalMarker?: string;
59
59
  /**
60
- * The layout variant for the label area.
61
- * Controls the visual styling and appearance of the label.
62
- * @default LabelLayout.HORIZONTAL_MAIN
60
+ * The spacing variant for the label area.
61
+ * Controls the padding and min-height of the label.
62
+ * Only applicable when layout is 'horizontal' or 'stretch'.
63
+ * Ignored when layout is 'vertical'.
64
+ * @default FormFieldLabelSpacing.MAIN
63
65
  */
64
- labelLayout?: LabelLayout;
66
+ labelSpacing?: FormFieldLabelSpacing;
67
+ /**
68
+ * The layout variant of the form field.
69
+ * Controls the arrangement direction of label and input.
70
+ * When set to 'vertical', density and labelSpacing are ignored.
71
+ * @default FormFieldLayout.HORIZONTAL
72
+ */
73
+ layout?: FormFieldLayout;
74
+ /**
75
+ * The density variant of the form field.
76
+ * Controls the width of label and max-width of data entry.
77
+ * Only applicable when layout is 'horizontal' or 'stretch'.
78
+ * Ignored when layout is 'vertical'.
79
+ */
80
+ density?: FormFieldDensity;
65
81
  /**
66
82
  * The name attribute for the form field.
67
83
  * Used to identify the field in form submissions and as htmlFor in the label.
@@ -71,11 +87,6 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
71
87
  * To control the field passed from children whether should be required.
72
88
  */
73
89
  required?: boolean;
74
- /**
75
- * The size variant of the form field.
76
- * Controls the layout and spacing of label, input, and other elements.
77
- */
78
- size: FormFieldSize;
79
90
  /**
80
91
  * The severity level of the form field.
81
92
  * Used to indicate the importance or urgency of the field.
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 { ControlFieldSlotLayout, LabelLayout, formFieldClasses, FormFieldCounterColor } from '@mezzanine-ui/core/form';
3
+ import { ControlFieldSlotLayout, FormFieldLabelSpacing, FormFieldLayout, 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,17 +10,25 @@ 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, 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;
13
+ const { children, className, counter, counterColor, controlFieldSlotLayout = ControlFieldSlotLayout.MAIN, density, disabled = false, fullWidth = false, hintText, hintTextIcon, label, labelInformationIcon, labelInformationText, labelOptionalMarker, labelSpacing = FormFieldLabelSpacing.MAIN, layout = FormFieldLayout.HORIZONTAL, name, required = false, severity = 'info', ...rest } = props;
14
14
  const formControl = {
15
15
  disabled,
16
16
  fullWidth,
17
17
  required,
18
18
  severity,
19
19
  };
20
- return (jsx("div", { ...rest, ref: ref, className: cx(formFieldClasses.host, formFieldClasses.size(size), {
20
+ const shouldApplyDensity = density && layout !== FormFieldLayout.VERTICAL;
21
+ const densityClass = shouldApplyDensity
22
+ ? formFieldClasses.density(density)
23
+ : undefined;
24
+ const shouldApplyLabelSpacing = layout !== FormFieldLayout.VERTICAL;
25
+ const labelSpacingClass = shouldApplyLabelSpacing
26
+ ? formFieldClasses.labelSpacing(labelSpacing)
27
+ : undefined;
28
+ return (jsx("div", { ...rest, ref: ref, className: cx(formFieldClasses.host, formFieldClasses.layout(layout), densityClass, {
21
29
  [formFieldClasses.disabled]: disabled,
22
30
  [formFieldClasses.fullWidth]: fullWidth,
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, {
31
+ }, className), children: jsxs(FormControlContext.Provider, { value: formControl, children: [label && (jsx(FormLabel, { className: cx(formFieldClasses.labelArea, labelSpacingClass), 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
32
  [formFieldClasses.hintTextAndCounterArea + '--align-right']: !(hintText || hintTextIcon) && counter,
25
33
  }), 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
34
  });
package/Input/Input.js CHANGED
@@ -124,6 +124,7 @@ const Input = forwardRef(function Input(props, ref) {
124
124
  break;
125
125
  }
126
126
  case 'currency': {
127
+ // 需注意 input type 不應是 number,因為要允許輸入格式化後的字串(例如 1,000)
127
128
  const currencyProps = props;
128
129
  const { step = 1, max, min, onSpinUp, onSpinDown } = currencyProps;
129
130
  // 預設置右對齊
@@ -166,11 +167,17 @@ const Input = forwardRef(function Input(props, ref) {
166
167
  const { actionButton } = actionProps;
167
168
  if (actionButton.position === 'prefix') {
168
169
  const { ...restActionButtonProps } = actionButton;
169
- prefixExternalButton = (jsx(ActionButton, { ...restActionButtonProps, disabled: restActionButtonProps.disabled || disabled, size: size }));
170
+ const actionDisabled = typeof restActionButtonProps.disabled === 'boolean'
171
+ ? restActionButtonProps.disabled
172
+ : disabled || readonly;
173
+ prefixExternalButton = (jsx(ActionButton, { ...restActionButtonProps, disabled: actionDisabled, size: size }));
170
174
  }
171
175
  if (actionButton.position === 'suffix') {
172
176
  const { ...restActionButtonProps } = actionButton;
173
- suffixExternalButton = (jsx(ActionButton, { ...restActionButtonProps, disabled: restActionButtonProps.disabled || disabled, size: size }));
177
+ const actionDisabled = typeof restActionButtonProps.disabled === 'boolean'
178
+ ? restActionButtonProps.disabled
179
+ : disabled || readonly;
180
+ suffixExternalButton = (jsx(ActionButton, { ...restActionButtonProps, disabled: actionDisabled, size: size }));
174
181
  }
175
182
  break;
176
183
  }
@@ -5,8 +5,8 @@ import { messageClasses, messageIcons } from '@mezzanine-ui/core/message';
5
5
  import { messageTimerController } from './MessageTimerController.js';
6
6
  import Translate from '../Transition/Translate.js';
7
7
  import Icon from '../Icon/Icon.js';
8
- import { createNotifier } from '../Notifier/createNotifier.js';
9
8
  import cx from 'clsx';
9
+ import { createNotifier } from '../Notifier/createNotifier.js';
10
10
 
11
11
  /**
12
12
  * The react component for `mezzanine` message.
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import { forwardRef, useState, useCallback, useEffect, useMemo, useRef } from 'react';
4
3
  import { getDefaultModeFormat, calendarClasses } from '@mezzanine-ui/core/calendar';
5
4
  import { multipleDatePickerClasses } from '@mezzanine-ui/core/multiple-date-picker';
6
5
  import { CalendarIcon } from '@mezzanine-ui/icons';
6
+ import { forwardRef, useState, useCallback, useEffect, useMemo, useRef } from 'react';
7
7
  import CalendarFooterActions from '../Calendar/CalendarFooterActions.js';
8
+ import { useComposeRefs } from '../hooks/useComposeRefs.js';
8
9
  import MultipleDatePickerTrigger from './MultipleDatePickerTrigger.js';
9
10
  import { useMultipleDatePickerValue } from './useMultipleDatePickerValue.js';
10
- import { useComposeRefs } from '../hooks/useComposeRefs.js';
11
11
  import { useCalendarContext } from '../Calendar/CalendarContext.js';
12
12
  import { useCalendarControls } from '../Calendar/useCalendarControls.js';
13
13
  import { usePickerDocumentEventClose } from '../Picker/usePickerDocumentEventClose.js';
@@ -10,7 +10,7 @@ const NavigationHeader = forwardRef((props, ref) => {
10
10
  const { children, className, title, onBrandClick, ...rest } = props;
11
11
  const { collapsed, handleCollapseChange } = use(NavigationActivatedContext);
12
12
  const BrandComponent = onBrandClick ? 'button' : 'span';
13
- return (jsxs("header", { ...rest, ref: ref, className: cx(navigationHeaderClasses.host, collapsed && navigationHeaderClasses.collapsed, className), children: [jsx(NavigationIconButton, { onClick: () => handleCollapseChange(!collapsed), icon: SiderIcon }), jsxs(BrandComponent, { type: "button", className: navigationHeaderClasses.content, onClick: onBrandClick, children: [children, jsx("span", { className: navigationHeaderClasses.title, children: title })] })] }));
13
+ return (jsxs("header", { ...rest, ref: ref, className: cx(navigationHeaderClasses.host, collapsed && navigationHeaderClasses.collapsed, className), children: [jsx(NavigationIconButton, { onClick: () => handleCollapseChange(!collapsed), icon: SiderIcon }), jsxs(BrandComponent, { type: "button", className: navigationHeaderClasses.content, onClick: onBrandClick, children: [children, jsx("span", { className: navigationHeaderClasses.title, children: collapsed ? title === null || title === void 0 ? void 0 : title[0] : title })] })] }));
14
14
  });
15
15
 
16
16
  export { NavigationHeader as default };
@@ -1,6 +1,6 @@
1
1
  import { InputHTMLAttributes } from 'react';
2
2
  import { type UseDateInputFormatterProps } from './useDateInputFormatter';
3
- export interface FormattedInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>, Pick<UseDateInputFormatterProps, 'errorMessages' | 'validate' | 'format' | 'onChange'> {
3
+ export interface FormattedInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>, Pick<UseDateInputFormatterProps, 'errorMessages' | 'validate' | 'format' | 'onChange' | 'onPasteIsoValue'> {
4
4
  /**
5
5
  * Placeholder to show when not focused and value is empty
6
6
  */
@@ -14,7 +14,7 @@ const FormattedInput = forwardRef(function FormattedInput(props, ref) {
14
14
  enabled: true,
15
15
  invalidInput: 'Input value is not valid.',
16
16
  invalidPaste: 'Pasted content is not valid.',
17
- }, format, placeholder, validate, value: externalValue, onChange, onFocus, onBlur, ...inputProps } = props;
17
+ }, format, placeholder, validate, value: externalValue, onChange, onFocus, onBlur, onPasteIsoValue, ...inputProps } = props;
18
18
  const internalInputRef = useRef(null);
19
19
  const composedRef = useComposeRefs([ref, internalInputRef]);
20
20
  const { value, focused, handleKeyDown, handleFocus, handleBlur, handlePaste, } = useDateInputFormatter({
@@ -26,6 +26,7 @@ const FormattedInput = forwardRef(function FormattedInput(props, ref) {
26
26
  onFocus,
27
27
  onBlur,
28
28
  validate,
29
+ onPasteIsoValue,
29
30
  });
30
31
  const segments = useRef(parseFormatSegments(format)).current;
31
32
  const renderMixedColorDisplay = () => {
@@ -63,6 +63,16 @@ export interface PickerTriggerWithSeparatorProps extends Omit<TextFieldProps, 'a
63
63
  * Can be used to trigger auto-focus to right input.
64
64
  */
65
65
  onLeftComplete?: () => void;
66
+ /**
67
+ * Callback when a valid ISO date is pasted into the left input.
68
+ * Allows parent to sync other fields (e.g., update time when date+time is pasted).
69
+ */
70
+ onPasteIsoValueLeft?: (isoValue: string) => void;
71
+ /**
72
+ * Callback when a valid ISO date is pasted into the right input.
73
+ * Allows parent to sync other fields (e.g., update date when date+time is pasted).
74
+ */
75
+ onPasteIsoValueRight?: (isoValue: string) => void;
66
76
  /**
67
77
  * Callback when right input is completed (all mask positions filled with valid value).
68
78
  */
@@ -12,7 +12,7 @@ import cx from 'clsx';
12
12
  * typically used for date-time pickers where left is date and right is time.
13
13
  */
14
14
  const PickerTriggerWithSeparator = forwardRef(function PickerTriggerWithSeparator(props, ref) {
15
- const { className, clearable = true, disabled, errorMessagesLeft, errorMessagesRight, formatLeft, formatRight, inputLeftProps, inputLeftRef: inputLeftRefProp, inputRightProps, inputRightRef: inputRightRefProp, onBlurLeft, onBlurRight, onChangeLeft, onChangeRight, onFocusLeft, onFocusRight, onLeftComplete, onRightComplete, placeholderLeft, placeholderRight, readOnly, required, suffix, validateLeft, validateRight, valueLeft, valueRight, ...restTextFieldProps } = props;
15
+ const { className, clearable = true, disabled, errorMessagesLeft, errorMessagesRight, formatLeft, formatRight, inputLeftProps, inputLeftRef: inputLeftRefProp, inputRightProps, inputRightRef: inputRightRefProp, onBlurLeft, onBlurRight, onChangeLeft, onChangeRight, onFocusLeft, onFocusRight, onLeftComplete, onPasteIsoValueLeft, onPasteIsoValueRight, onRightComplete, placeholderLeft, placeholderRight, readOnly, required, suffix, validateLeft, validateRight, valueLeft, valueRight, ...restTextFieldProps } = props;
16
16
  const internalLeftRef = useRef(null);
17
17
  const internalRightRef = useRef(null);
18
18
  const leftRef = useComposeRefs([
@@ -74,7 +74,7 @@ const PickerTriggerWithSeparator = forwardRef(function PickerTriggerWithSeparato
74
74
  const handleRightBlur = useCallback((e) => {
75
75
  onBlurRight === null || onBlurRight === void 0 ? void 0 : onBlurRight(e);
76
76
  }, [onBlurRight]);
77
- return (jsx(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, className), clearable: !readOnly && clearable, suffix: suffix, children: jsxs("div", { className: pickerClasses.separatorInputs, children: [jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputLeftProps, ref: leftRef, "aria-disabled": disabled, "aria-label": "Date input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesLeft, format: formatLeft, onBlur: handleLeftBlur, onChange: handleLeftChange, onFocus: handleLeftFocus, placeholder: placeholderLeft, readOnly: readOnly, required: required, validate: validateLeft, value: valueLeft }) }), jsx("div", { className: pickerClasses.separator }), jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputRightProps, ref: rightRef, "aria-disabled": disabled, "aria-label": "Time input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesRight, format: formatRight, onBlur: handleRightBlur, onChange: handleRightChange, onFocus: handleRightFocus, placeholder: placeholderRight, readOnly: readOnly, required: required, validate: validateRight, value: valueRight }) })] }) }));
77
+ return (jsx(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, className), clearable: !readOnly && clearable, suffix: suffix, children: jsxs("div", { className: pickerClasses.separatorInputs, children: [jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputLeftProps, ref: leftRef, "aria-disabled": disabled, "aria-label": "Date input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesLeft, format: formatLeft, onBlur: handleLeftBlur, onChange: handleLeftChange, onFocus: handleLeftFocus, onPasteIsoValue: onPasteIsoValueLeft, placeholder: placeholderLeft, readOnly: readOnly, required: required, validate: validateLeft, value: valueLeft }) }), jsx("div", { className: pickerClasses.separator }), jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputRightProps, ref: rightRef, "aria-disabled": disabled, "aria-label": "Time input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesRight, format: formatRight, onBlur: handleRightBlur, onChange: handleRightChange, onFocus: handleRightFocus, onPasteIsoValue: onPasteIsoValueRight, placeholder: placeholderRight, readOnly: readOnly, required: required, validate: validateRight, value: valueRight }) })] }) }));
78
78
  });
79
79
 
80
80
  export { PickerTriggerWithSeparator, PickerTriggerWithSeparator as default };
@@ -38,6 +38,12 @@ export interface UseDateInputFormatterProps {
38
38
  * Called after format validation passes.
39
39
  */
40
40
  validate?: (isoDate: string) => boolean;
41
+ /**
42
+ * Callback when a valid ISO date is pasted.
43
+ * This allows parent components to handle cross-field updates
44
+ * (e.g., updating time field when date+time is pasted into date field).
45
+ */
46
+ onPasteIsoValue?: (isoValue: string) => void;
41
47
  }
42
48
  /**
43
49
  * Hook for formatting date/time input with mask format
@@ -12,7 +12,7 @@ function useDateInputFormatter(props) {
12
12
  enabled: true,
13
13
  invalidInput: 'Input value is not valid.',
14
14
  invalidPaste: 'Pasted content is not valid.',
15
- }, format, value: externalValue = '', onChange, inputRef, onFocus: onFocusProp, onBlur: onBlurProp, validate, } = props;
15
+ }, format, value: externalValue = '', onChange, inputRef, onFocus: onFocusProp, onBlur: onBlurProp, validate, onPasteIsoValue, } = props;
16
16
  const { parseFormattedValue, isValid, locale, formatToString } = useCalendarContext();
17
17
  const maskFormat = useRef(new MaskFormat(format)).current;
18
18
  const [internalValue, setInternalValue] = useState(externalValue || getTemplateWithoutBrackets(format));
@@ -325,6 +325,8 @@ function useDateInputFormatter(props) {
325
325
  // If pasted data is a valid ISO date, format it accordingly
326
326
  const parsedDate = formatToString(locale, pasteData, format);
327
327
  if (parsedDate) {
328
+ // Notify parent about the full ISO value for cross-field sync
329
+ onPasteIsoValue === null || onPasteIsoValue === void 0 ? void 0 : onPasteIsoValue(pasteData);
328
330
  triggerChange(parsedDate);
329
331
  return;
330
332
  }
@@ -363,6 +365,7 @@ function useDateInputFormatter(props) {
363
365
  errorMessages,
364
366
  internalValue,
365
367
  maskFormat,
368
+ onPasteIsoValue,
366
369
  triggerChange,
367
370
  isValid,
368
371
  format,
@@ -1,17 +1,11 @@
1
1
  import { DropdownOption, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
2
2
  import { SelectInputSize } from '@mezzanine-ui/core/select';
3
- import React, { ReactElement } from 'react';
4
3
  import { FormElementFocusHandlers } from '../Form';
5
4
  import { SelectTriggerInputProps, SelectTriggerProps, SelectValue } from './typings';
6
5
  export interface SelectBaseProps extends Omit<SelectTriggerProps, 'active' | 'inputProps' | 'mode' | 'onBlur' | 'onChange' | 'onClick' | 'onFocus' | 'onKeyDown' | 'onScroll' | 'type' | 'renderValue' | 'value'>, FormElementFocusHandlers {
7
- /**
8
- * The children of select (Option components).
9
- * If `options` is provided, this will be ignored.
10
- */
11
- children?: ReactElement | ReactElement[];
12
6
  /**
13
7
  * Direct options array for dropdown (supports tree structure).
14
- * If provided, `children` will be ignored and `type` will be automatically set.
8
+ * If provided, `type` will be automatically set.
15
9
  */
16
10
  options?: DropdownOption[];
17
11
  /**
@@ -113,5 +107,5 @@ export type SelectSingleProps = SelectBaseProps & {
113
107
  value?: SelectValue | null;
114
108
  };
115
109
  export type SelectProps = SelectMultipleProps | SelectSingleProps;
116
- declare const Select: React.ForwardRefExoticComponent<SelectProps & React.RefAttributes<HTMLDivElement>>;
110
+ declare const Select: import("react").ForwardRefExoticComponent<SelectProps & import("react").RefAttributes<HTMLDivElement>>;
117
111
  export default Select;
package/Select/Select.js CHANGED
@@ -2,10 +2,9 @@
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { selectClasses } from '@mezzanine-ui/core/select';
4
4
  import isArray from 'lodash/isArray';
5
- import React, { forwardRef, useContext, useState, useCallback, useRef, useMemo, Children } from 'react';
5
+ import { forwardRef, useContext, useState, useCallback, useRef, useMemo } from 'react';
6
6
  import { useSelectValueControl } from '../Form/useSelectValueControl.js';
7
7
  import { useComposeRefs } from '../hooks/useComposeRefs.js';
8
- import Option from './Option.js';
9
8
  import { SelectControlContext } from './SelectControlContext.js';
10
9
  import SelectTrigger from './SelectTrigger.js';
11
10
  import { FormControlContext } from '../Form/FormControlContext.js';
@@ -14,7 +13,7 @@ import cx from 'clsx';
14
13
 
15
14
  const Select = forwardRef(function Select(props, ref) {
16
15
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
17
- const { children, className, clearable = false, defaultValue, disabled = disabledFromFormControl || false, error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, inputProps, inputRef, menuMaxHeight, mode = 'single', onBlur, onChange: onChangeProp, onClear: onClearProp, onFocus, onScroll, options: optionsProp, placeholder = '', prefix, readOnly = false, renderValue, required = requiredFromFormControl || false, size, suffixActionIcon, type = 'default', value: valueProp, dropdownZIndex, globalPortal = true, } = props;
16
+ const { className, clearable = false, defaultValue, disabled = disabledFromFormControl || false, error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, inputProps, inputRef, menuMaxHeight, mode = 'single', onBlur, onChange: onChangeProp, onClear: onClearProp, onFocus, onScroll, options: optionsProp, placeholder = '', prefix, readOnly = false, renderValue, required = requiredFromFormControl || false, size, suffixActionIcon, type = 'default', value: valueProp, dropdownZIndex, globalPortal = true, } = props;
18
17
  const [open, toggleOpen] = useState(false);
19
18
  const onOpen = useCallback(() => {
20
19
  // Prevent opening when readOnly is true
@@ -78,39 +77,19 @@ const Select = forwardRef(function Select(props, ref) {
78
77
  }
79
78
  return null;
80
79
  }, []);
81
- // Convert children (Option components) to DropdownOption format
82
- // Or use provided options directly
80
+ // Use provided options directly
83
81
  const options = useMemo(() => {
84
- // If options prop is provided, use it directly
85
- if (optionsProp) {
86
- // In tree mode (multiple mode with tree structure), ensure all options have checkbox
87
- if (mode === 'multiple') {
88
- const hasTreeStructure = optionsProp.some((opt) => opt.children && opt.children.length > 0);
89
- if (hasTreeStructure) {
90
- return addCheckboxToTreeOptions(optionsProp);
91
- }
82
+ if (!optionsProp)
83
+ return [];
84
+ // In tree mode (multiple mode with tree structure), ensure all options have checkbox
85
+ if (mode === 'multiple') {
86
+ const hasTreeStructure = optionsProp.some((opt) => opt.children && opt.children.length > 0);
87
+ if (hasTreeStructure) {
88
+ return addCheckboxToTreeOptions(optionsProp);
92
89
  }
93
- return optionsProp;
94
90
  }
95
- // Otherwise, convert children to options
96
- if (!children)
97
- return [];
98
- return Children.toArray(children)
99
- .filter((child) => {
100
- var _a;
101
- return (React.isValidElement(child) &&
102
- (child.type === Option || ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'Option'));
103
- })
104
- .map((child) => {
105
- const props = child.props;
106
- return {
107
- id: props.value,
108
- name: props.children,
109
- showCheckbox: mode === 'multiple',
110
- checkSite: mode === 'multiple' ? 'prefix' : 'suffix',
111
- };
112
- });
113
- }, [children, mode, optionsProp, addCheckboxToTreeOptions]);
91
+ return optionsProp;
92
+ }, [mode, optionsProp, addCheckboxToTreeOptions]);
114
93
  // Determine dropdown type based on options structure and mode
115
94
  // Tree mode is only available in multiple mode
116
95
  const dropdownType = useMemo(() => {
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { forwardRef } from 'react';
4
3
  import { selectClasses } from '@mezzanine-ui/core/select';
5
4
  import { ChevronDownIcon } from '@mezzanine-ui/icons';
5
+ import { forwardRef } from 'react';
6
6
  import SelectTriggerTags from './SelectTriggerTags.js';
7
7
  import Icon from '../Icon/Icon.js';
8
8
  import TextField from '../TextField/TextField.js';
@@ -12,24 +12,36 @@ const isMultipleSelection = (props) => props.mode === 'multiple';
12
12
  function SelectTriggerComponent(props) {
13
13
  var _a, _b, _c;
14
14
  const { active, className, disabled, forceHideSuffixActionIcon, inputProps, innerRef, inputRef, isForceClearable = false, mode = 'single', onTagClose, overflowStrategy = 'counter', placeholder, readOnly, required, searchText, size = 'main', showTextInputAfterTags = false, suffixAction, suffixActionIcon: suffixActionIconProp, type = 'default', onClick, ...restTextFieldProps } = props;
15
+ const renderValueProp = 'renderValue' in props ? props.renderValue : undefined;
16
+ // Exclude renderValue to avoid leaking unknown props to DOM.
17
+ const sanitizedTextFieldProps = (() => {
18
+ if ('renderValue' in restTextFieldProps) {
19
+ const { renderValue: _removed, ...rest } = restTextFieldProps;
20
+ return rest;
21
+ }
22
+ return restTextFieldProps;
23
+ })();
15
24
  /** Render value to string for single selection trigger input */
16
25
  const renderValue = () => {
17
26
  var _a, _b;
18
27
  if (isMultipleSelection(props))
19
28
  return;
20
- if (typeof props.renderValue === 'function') {
21
- return props.renderValue(props.value);
29
+ if (typeof renderValueProp === 'function') {
30
+ return renderValueProp(props.value);
22
31
  }
23
32
  return (_b = (_a = props.value) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
24
33
  };
25
34
  /** Compute suffix action icon */
26
35
  const suffixActionIcon = suffixActionIconProp || (jsx(Icon, { icon: ChevronDownIcon, onClick: (e) => {
36
+ var _a;
27
37
  e.stopPropagation();
28
38
  if (suffixAction) {
29
39
  suffixAction();
30
40
  }
31
41
  else {
32
- onClick === null || onClick === void 0 ? void 0 : onClick(e);
42
+ // Delegate to trigger click behavior without fabricating a synthetic event.
43
+ (_a = e.currentTarget
44
+ .closest(`.${selectClasses.trigger}`)) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new MouseEvent('click', { bubbles: true }));
33
45
  }
34
46
  }, className: cx(selectClasses.triggerSuffixActionIcon, {
35
47
  [selectClasses.triggerSuffixActionIconActive]: active,
@@ -43,7 +55,7 @@ function SelectTriggerComponent(props) {
43
55
  }
44
56
  return {};
45
57
  })();
46
- return (jsxs(TextField, { ref: innerRef, ...interactiveProps, ...restTextFieldProps, onClick: onClick, active: active, className: cx(selectClasses.trigger, selectClasses.triggerMode(mode), selectClasses.triggerSelected(Array.isArray(props.value) ? (_a = props.value) === null || _a === void 0 ? void 0 : _a.length : props.value), {
58
+ return (jsxs(TextField, { ref: innerRef, ...interactiveProps, ...sanitizedTextFieldProps, onClick: onClick, active: active, className: cx(selectClasses.trigger, selectClasses.triggerMode(mode), selectClasses.triggerSelected(Array.isArray(props.value) ? (_a = props.value) === null || _a === void 0 ? void 0 : _a.length : props.value), {
47
59
  [selectClasses.triggerReadOnly]: readOnly,
48
60
  [selectClasses.triggerDisabled]: disabled,
49
61
  }, className), error: type === 'error', size: size, suffix: forceHideSuffixActionIcon ? undefined : suffixActionIcon, clearable: isForceClearable ||
@@ -53,9 +65,11 @@ function SelectTriggerComponent(props) {
53
65
  }
54
66
  const SelectTrigger = forwardRef((props, ref) => {
55
67
  if (props.mode === 'multiple') {
56
- return (jsx(SelectTriggerComponent, { ...props, innerRef: ref }));
68
+ const { mode: _mode, value, ...multipleModeProps } = props;
69
+ return (jsx(SelectTriggerComponent, { ...multipleModeProps, innerRef: ref, mode: "multiple", value: Array.isArray(value) ? value : undefined }));
57
70
  }
58
- return (jsx(SelectTriggerComponent, { ...props, innerRef: ref }));
71
+ const { mode: _mode, overflowStrategy: _overflowStrategy, value, ...singleModeProps } = props;
72
+ return (jsx(SelectTriggerComponent, { ...singleModeProps, innerRef: ref, mode: "single", value: Array.isArray(value) ? undefined : value }));
59
73
  });
60
74
 
61
75
  export { SelectTrigger as default };
package/Select/index.d.ts CHANGED
@@ -1,13 +1,9 @@
1
1
  export { default as OptionGroup } from '../Menu/MenuItemGroup';
2
2
  export type { MenuItemGroupProps as OptionGroupProps } from '../Menu/MenuItemGroup';
3
- export { default as Option } from './Option';
4
- export type { OptionProps } from './Option';
5
3
  export { default } from './Select';
6
4
  export type { SelectProps } from './Select';
7
5
  export { SelectControlContext } from './SelectControlContext';
8
6
  export { default as SelectTrigger } from './SelectTrigger';
9
7
  export { default as SelectTriggerTags } from './SelectTriggerTags';
10
8
  export type { SelectTriggerTagsProps } from './SelectTriggerTags';
11
- export { default as TreeSelect } from './TreeSelect';
12
- export type { TreeSelectProps } from './TreeSelect';
13
9
  export * from './typings';
package/Select/index.js CHANGED
@@ -1,7 +1,5 @@
1
1
  export { default as OptionGroup } from '../Menu/MenuItemGroup.js';
2
- export { default as Option } from './Option.js';
3
2
  export { default } from './Select.js';
4
3
  export { SelectControlContext } from './SelectControlContext.js';
5
4
  export { default as SelectTrigger } from './SelectTrigger.js';
6
5
  export { default as SelectTriggerTags } from './SelectTriggerTags.js';
7
- export { default as TreeSelect } from './TreeSelect.js';