@mezzanine-ui/react 1.0.0-rc.0 → 1.0.0-rc.2

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 (64) hide show
  1. package/Badge/Badge.d.ts +4 -0
  2. package/Badge/Badge.js +2 -2
  3. package/Badge/typings.d.ts +13 -1
  4. package/Calendar/CalendarDays.js +4 -3
  5. package/Calendar/CalendarWeeks.js +4 -3
  6. package/Cascader/Cascader.d.ts +3 -0
  7. package/Cascader/Cascader.js +241 -0
  8. package/Cascader/CascaderPanel.d.ts +29 -0
  9. package/Cascader/CascaderPanel.js +29 -0
  10. package/Cascader/index.d.ts +5 -0
  11. package/Cascader/index.js +2 -0
  12. package/Cascader/typings.d.ts +92 -0
  13. package/Description/Description.d.ts +6 -1
  14. package/Description/Description.js +11 -4
  15. package/Description/DescriptionContent.d.ts +9 -3
  16. package/Description/DescriptionContent.js +4 -1
  17. package/Description/DescriptionContext.d.ts +6 -0
  18. package/Description/DescriptionContext.js +9 -0
  19. package/Description/index.d.ts +2 -0
  20. package/Description/index.js +1 -0
  21. package/Form/FormField.d.ts +6 -0
  22. package/Form/FormField.js +2 -2
  23. package/Form/FormHintText.d.ts +12 -0
  24. package/Form/FormHintText.js +3 -2
  25. package/Layout/Layout.d.ts +21 -5
  26. package/Layout/Layout.js +23 -19
  27. package/Layout/LayoutContext.d.ts +6 -6
  28. package/Layout/LayoutContext.js +2 -2
  29. package/Layout/LayoutHost.d.ts +0 -4
  30. package/Layout/LayoutHost.js +16 -13
  31. package/Layout/LayoutLeftPanel.d.ts +19 -0
  32. package/Layout/LayoutLeftPanel.js +86 -0
  33. package/Layout/LayoutMain.d.ts +10 -1
  34. package/Layout/LayoutMain.js +12 -3
  35. package/Layout/LayoutRightPanel.d.ts +19 -0
  36. package/Layout/{LayoutSidePanel.js → LayoutRightPanel.js} +32 -36
  37. package/Layout/index.d.ts +2 -2
  38. package/Layout/index.js +2 -1
  39. package/Modal/MediaPreviewModal.d.ts +4 -0
  40. package/Modal/MediaPreviewModal.js +2 -2
  41. package/Modal/Modal.d.ts +4 -0
  42. package/Modal/Modal.js +2 -2
  43. package/Modal/useModalContainer.js +0 -1
  44. package/Navigation/Navigation.d.ts +4 -0
  45. package/Navigation/Navigation.js +39 -3
  46. package/Navigation/NavigationFooter.js +19 -2
  47. package/Navigation/NavigationOption.d.ts +4 -0
  48. package/Navigation/NavigationOption.js +40 -19
  49. package/Navigation/NavigationOverflowMenuOption.js +11 -7
  50. package/Navigation/NavigationUserMenu.d.ts +1 -0
  51. package/Navigation/NavigationUserMenu.js +24 -5
  52. package/Navigation/context.d.ts +2 -0
  53. package/Navigation/context.js +4 -1
  54. package/Picker/RangePickerTrigger.js +1 -1
  55. package/Section/Section.js +6 -6
  56. package/Transition/Collapse.d.ts +2 -1
  57. package/Transition/Collapse.js +2 -1
  58. package/Upload/Upload.js +63 -9
  59. package/Upload/UploadPictureCard.d.ts +25 -15
  60. package/Upload/UploadPictureCard.js +14 -6
  61. package/index.d.ts +4 -2
  62. package/index.js +4 -1
  63. package/package.json +4 -4
  64. package/Layout/LayoutSidePanel.d.ts +0 -14
package/Modal/Modal.js CHANGED
@@ -12,14 +12,14 @@ import cx from 'clsx';
12
12
  * The react component for `mezzanine` modal.
13
13
  */
14
14
  const Modal = forwardRef(function Modal(props, ref) {
15
- const { actionsButtonLayout, annotation, auxiliaryContentButtonProps, auxiliaryContentButtonText, auxiliaryContentChecked, auxiliaryContentLabel, auxiliaryContentOnChange, auxiliaryContentOnClick, auxiliaryContentType, cancelButtonProps, cancelText, children, className, confirmButtonProps, confirmText, container, disableCloseOnBackdropClick = false, disableCloseOnEscapeKeyDown = false, disablePortal = false, extendedSplitLeftSideContent, extendedSplitRightSideContent, fullScreen = false, loading = false, modalStatusType = 'info', modalType = 'standard', onBackdropClick, onCancel, onClose, onConfirm, open, passwordButtonProps, passwordButtonText, passwordChecked, passwordCheckedLabel, passwordCheckedOnChange, passwordOnClick, showCancelButton, showDismissButton = true, showModalFooter = false, showModalHeader, showStatusTypeIcon, size = 'regular', statusTypeIconLayout, supportingText, supportingTextAlign, title, titleAlign, ...rest } = props;
15
+ const { actionsButtonLayout, annotation, auxiliaryContentButtonProps, auxiliaryContentButtonText, auxiliaryContentChecked, auxiliaryContentLabel, auxiliaryContentOnChange, auxiliaryContentOnClick, auxiliaryContentType, backdropClassName, cancelButtonProps, cancelText, children, className, confirmButtonProps, confirmText, container, disableCloseOnBackdropClick = false, disableCloseOnEscapeKeyDown = false, disablePortal = false, extendedSplitLeftSideContent, extendedSplitRightSideContent, fullScreen = false, loading = false, modalStatusType = 'info', modalType = 'standard', onBackdropClick, onCancel, onClose, onConfirm, open, passwordButtonProps, passwordButtonText, passwordChecked, passwordCheckedLabel, passwordCheckedOnChange, passwordOnClick, showCancelButton, showDismissButton = true, showModalFooter = false, showModalHeader, showStatusTypeIcon, size = 'regular', statusTypeIconLayout, supportingText, supportingTextAlign, title, titleAlign, ...rest } = props;
16
16
  const modalControl = useMemo(() => ({
17
17
  loading,
18
18
  modalStatusType: modalStatusType,
19
19
  }), [loading, modalStatusType]);
20
20
  const { Container: ModalContainer } = useModalContainer();
21
21
  const renderModalFooter = () => (jsx(ModalFooter, { actionsButtonLayout: actionsButtonLayout, annotation: annotation, auxiliaryContentButtonProps: auxiliaryContentButtonProps, auxiliaryContentButtonText: auxiliaryContentButtonText, auxiliaryContentChecked: auxiliaryContentChecked, auxiliaryContentLabel: auxiliaryContentLabel, auxiliaryContentOnChange: auxiliaryContentOnChange, auxiliaryContentOnClick: auxiliaryContentOnClick, auxiliaryContentType: auxiliaryContentType, cancelButtonProps: cancelButtonProps, cancelText: cancelText, confirmButtonProps: confirmButtonProps, confirmText: confirmText, loading: loading, onCancel: onCancel, onConfirm: onConfirm, passwordButtonProps: passwordButtonProps, passwordButtonText: passwordButtonText, passwordChecked: passwordChecked, passwordCheckedLabel: passwordCheckedLabel, passwordCheckedOnChange: passwordCheckedOnChange, passwordOnClick: passwordOnClick, showCancelButton: showCancelButton }));
22
- return (jsx(ModalControlContext.Provider, { value: modalControl, children: jsx(ModalContainer, { className: modalClasses.overlay, container: container, disableCloseOnBackdropClick: disableCloseOnBackdropClick, disableCloseOnEscapeKeyDown: disableCloseOnEscapeKeyDown, disablePortal: disablePortal, onBackdropClick: onBackdropClick, onClose: onClose, open: open, ref: ref, children: jsxs("div", { ...rest, className: cx(modalClasses.host, modalClasses.modalStatusType(modalStatusType), modalClasses.size(size), {
22
+ return (jsx(ModalControlContext.Provider, { value: modalControl, children: jsx(ModalContainer, { className: backdropClassName, container: container, disableCloseOnBackdropClick: disableCloseOnBackdropClick, disableCloseOnEscapeKeyDown: disableCloseOnEscapeKeyDown, disablePortal: disablePortal, onBackdropClick: onBackdropClick, onClose: onClose, open: open, ref: ref, children: jsxs("div", { ...rest, className: cx(modalClasses.host, modalClasses.modalStatusType(modalStatusType), modalClasses.size(size), {
23
23
  [modalClasses.fullScreen]: fullScreen,
24
24
  [modalClasses.withCloseIcon]: showDismissButton,
25
25
  }, className), role: "dialog", children: [showModalHeader && (jsx(ModalHeader, { showStatusTypeIcon: showStatusTypeIcon, statusTypeIconLayout: statusTypeIconLayout, supportingText: supportingText, supportingTextAlign: supportingTextAlign, title: title, titleAlign: titleAlign })), modalType === 'extendedSplit' && (jsxs("div", { className: modalClasses.modalBodyContainerExtendedSplit, children: [jsx("div", { className: modalClasses.modalBodyContainerExtendedSplitRight, children: extendedSplitRightSideContent }), jsxs("div", { className: modalClasses.modalBodyContainerExtendedSplitLeft, children: [jsx("div", { className: modalClasses.modalBodyContainerExtendedSplitLeftSideContent, children: extendedSplitLeftSideContent }), showModalFooter && renderModalFooter()] })] })), (modalType === 'standard' ||
@@ -9,7 +9,6 @@ import Scale from '../Transition/Scale.js';
9
9
  import cx from 'clsx';
10
10
 
11
11
  const defaultOptions = {
12
- className: modalClasses.overlay,
13
12
  disableCloseOnBackdropClick: false,
14
13
  disableCloseOnEscapeKeyDown: false,
15
14
  disablePortal: false,
@@ -32,6 +32,10 @@ export interface NavigationProps extends Omit<NativeElementPropsWithoutKeyAndRef
32
32
  * Called when a navigation option is clicked.
33
33
  */
34
34
  onOptionClick?: (activePath?: string[]) => void;
35
+ /**
36
+ * Custom component for rendering navigation options which have an href prop.
37
+ */
38
+ optionsAnchorComponent?: React.ElementType;
35
39
  }
36
40
  declare const Navigation: import("react").ForwardRefExoticComponent<NavigationProps & import("react").RefAttributes<HTMLElement>>;
37
41
  export default Navigation;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { forwardRef, useState, useCallback, useMemo, Children, isValidElement } from 'react';
3
+ import { forwardRef, useState, useCallback, useMemo, Children, isValidElement, useRef, useEffect } from 'react';
4
4
  import { navigationClasses } from '@mezzanine-ui/core/navigation';
5
5
  import NavigationOption from './NavigationOption.js';
6
6
  import NavigationHeader from './NavigationHeader.js';
@@ -15,17 +15,19 @@ import Input from '../Input/Input.js';
15
15
  import cx from 'clsx';
16
16
 
17
17
  const Navigation = forwardRef((props, ref) => {
18
- const { activatedPath, children = [], className, collapsed: collapsedProp, filter, onCollapseChange, onOptionClick, ...rest } = props;
18
+ const { activatedPath, children = [], className, collapsed: collapsedProp, filter, onCollapseChange, onOptionClick, optionsAnchorComponent, ...rest } = props;
19
19
  const [collapsedState, setCollapsedState] = useState(collapsedProp || false);
20
20
  const collapsed = collapsedProp !== null && collapsedProp !== void 0 ? collapsedProp : collapsedState;
21
21
  const handleCollapseChange = useCallback((newCollapsed) => {
22
22
  setCollapsedState(newCollapsed);
23
23
  onCollapseChange === null || onCollapseChange === void 0 ? void 0 : onCollapseChange(newCollapsed);
24
24
  }, [onCollapseChange]);
25
- const [innerActivatedPath, setInnerActivatedPath] = useState([]);
25
+ const [innerActivatedPath, setInnerActivatedPath] = useState(activatedPath || []);
26
+ const [activatedPathKey, setActivatedPathKey] = useState(activatedPath ? activatedPath.join('::') : '');
26
27
  const combineSetActivatedPath = useCallback((newActivatedPath) => {
27
28
  onOptionClick === null || onOptionClick === void 0 ? void 0 : onOptionClick(newActivatedPath);
28
29
  setInnerActivatedPath(newActivatedPath);
30
+ setActivatedPathKey(newActivatedPath.join('::'));
29
31
  }, [onOptionClick]);
30
32
  const currentPathname = useCurrentPathname();
31
33
  const flattenedChildren = useMemo(() => flattenChildren(children), [children]);
@@ -65,6 +67,38 @@ const Navigation = forwardRef((props, ref) => {
65
67
  });
66
68
  return { headerComponent, footerComponent, items, level1Items };
67
69
  }, [flattenedChildren]);
70
+ const hrefActivated = useRef(false);
71
+ // Scan level1Items and its descendants (up to level3) to find out whether href matches to determine whether to preset expansion and activatedPath
72
+ useEffect(() => {
73
+ if (hrefActivated.current || !currentPathname) {
74
+ return;
75
+ }
76
+ const checkActivatedPathKey = (items, path) => {
77
+ for (const item of items) {
78
+ if (!isValidElement(item) || item.type !== NavigationOption) {
79
+ continue;
80
+ }
81
+ const newKey = item.props.id || item.props.title || item.props.href;
82
+ if (!newKey) {
83
+ continue;
84
+ }
85
+ const newPath = [...path, newKey];
86
+ if (item.props.href && item.props.href === currentPathname) {
87
+ combineSetActivatedPath(newPath);
88
+ return true;
89
+ }
90
+ if (item.props.children) {
91
+ const flattenedChildren = flattenChildren(item.props.children);
92
+ if (checkActivatedPathKey(flattenedChildren, newPath)) {
93
+ return true;
94
+ }
95
+ }
96
+ }
97
+ return false;
98
+ };
99
+ checkActivatedPathKey(level1Items, []);
100
+ hrefActivated.current = true;
101
+ }, [combineSetActivatedPath, currentPathname, level1Items]);
68
102
  const { contentRef, visibleCount } = useVisibleItems(items, collapsed);
69
103
  const { collapsedItems, collapsedMenuItems } = useMemo(() => {
70
104
  return {
@@ -77,11 +111,13 @@ const Navigation = forwardRef((props, ref) => {
77
111
  const [filterText, setFilterText] = useState('');
78
112
  return (jsx("nav", { ...rest, ref: ref, className: cx(navigationClasses.host, collapsed ? navigationClasses.collapsed : navigationClasses.expand, className), children: jsxs(NavigationActivatedContext.Provider, { value: {
79
113
  activatedPath: activatedPath || innerActivatedPath,
114
+ activatedPathKey,
80
115
  collapsed,
81
116
  currentPathname,
82
117
  filterText,
83
118
  handleCollapseChange,
84
119
  setActivatedPath: combineSetActivatedPath,
120
+ optionsAnchorComponent,
85
121
  }, children: [headerComponent, jsx(NavigationOptionLevelContext.Provider, { value: navigationOptionLevelContextDefaultValues, children: jsxs("div", { ref: contentRef, className: navigationClasses.content, children: [filter && (jsx(Input, { size: "sub", variant: "search", className: cx(navigationClasses.searchInput), value: filterText, onChange: (e) => setFilterText(e.target.value) })), jsxs("ul", { children: [collapsed ? collapsedItems : items, collapsed &&
86
122
  visibleCount !== null &&
87
123
  visibleCount < level1Items.length && (jsx(NavigationOverflowMenu, { items: collapsedMenuItems }))] }, collapsed ? 'collapsed' : 'expand')] }) }), footerComponent] }) }));
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { forwardRef, use, Children, isValidElement } from 'react';
2
+ import { forwardRef, use, useRef, useState, useEffect, Children, isValidElement } from 'react';
3
3
  import { navigationFooterClasses } from '@mezzanine-ui/core/navigation';
4
4
  import NavigationUserMenu from './NavigationUserMenu.js';
5
5
  import { NavigationActivatedContext } from './context.js';
@@ -22,7 +22,24 @@ const NavigationFooter = forwardRef((props, ref) => {
22
22
  const { children, className, ...rest } = props;
23
23
  const { collapsed } = use(NavigationActivatedContext);
24
24
  const { userMenu, otherChildren } = resolveChildren(children);
25
- return (jsxs("footer", { ...rest, ref: ref, className: cx(navigationFooterClasses.host, collapsed && navigationFooterClasses.collapsed, className), children: [userMenu, jsx("span", { className: navigationFooterClasses.icons, children: otherChildren })] }));
25
+ const iconsRef = useRef(null);
26
+ const [iconsWidth, setIconsWidth] = useState(0);
27
+ useEffect(() => {
28
+ if (!iconsRef.current)
29
+ return;
30
+ const resizeObserver = new ResizeObserver(() => {
31
+ if (iconsRef.current) {
32
+ setIconsWidth(iconsRef.current.offsetWidth);
33
+ }
34
+ });
35
+ resizeObserver.observe(iconsRef.current);
36
+ return () => {
37
+ resizeObserver.disconnect();
38
+ };
39
+ }, []);
40
+ return (jsxs("footer", { ...rest, ref: ref, className: cx(navigationFooterClasses.host, collapsed && navigationFooterClasses.collapsed, className), style: {
41
+ ['--icons-width']: `${iconsWidth}px`,
42
+ }, children: [userMenu, jsx("span", { ref: iconsRef, className: navigationFooterClasses.icons, children: otherChildren })] }));
26
43
  });
27
44
 
28
45
  export { NavigationFooter as default };
@@ -13,6 +13,10 @@ export interface NavigationOptionProps extends Omit<NativeElementPropsWithoutKey
13
13
  * Strict children with `NavigationOption`.
14
14
  */
15
15
  children?: NavigationOptionChildren;
16
+ /**
17
+ * Custom component to render, it should support `href` and `onClick` props if provided.
18
+ */
19
+ anchorComponent?: React.ElementType;
16
20
  /**
17
21
  * Icon of the item.
18
22
  */
@@ -1,34 +1,32 @@
1
1
  'use client';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { forwardRef, useState, use, useId, useMemo, useEffect, Children, isValidElement } from 'react';
3
+ import { forwardRef, use, useState, useId, useMemo, Children, isValidElement, useEffect, useRef } from 'react';
4
4
  import { navigationOptionClasses } from '@mezzanine-ui/core/navigation';
5
5
  import { ChevronUpIcon, ChevronDownIcon } from '@mezzanine-ui/icons';
6
- import { NavigationOptionLevelContext, NavigationActivatedContext } from './context.js';
6
+ import { NavigationActivatedContext, NavigationOptionLevelContext } from './context.js';
7
7
  import { flattenChildren } from '../utils/flatten-children.js';
8
8
  import Badge from '../Badge/Badge.js';
9
9
  import Tooltip from '../Tooltip/Tooltip.js';
10
10
  import Icon from '../Icon/Icon.js';
11
+ import Fade from '../Transition/Fade.js';
11
12
  import Collapse from '../Transition/Collapse.js';
12
13
  import cx from 'clsx';
13
14
 
14
15
  const NavigationOption = forwardRef((props, ref) => {
15
- const { active, children, className, defaultOpen = false, href, icon, id, onTriggerClick, title, ...rest } = props;
16
- const [open, setOpen] = useState(defaultOpen);
16
+ var _a;
17
+ const { active, children, className, anchorComponent, defaultOpen, href, icon, id, onTriggerClick, title, ...rest } = props;
18
+ const { activatedPathKey, activatedPath, collapsed, filterText, handleCollapseChange, setActivatedPath, optionsAnchorComponent, } = use(NavigationActivatedContext);
19
+ const [open, setOpen] = useState(defaultOpen !== null && defaultOpen !== void 0 ? defaultOpen : false);
17
20
  const GroupToggleIcon = open ? ChevronUpIcon : ChevronDownIcon;
18
21
  const { level, path: parentPath } = use(NavigationOptionLevelContext);
19
22
  const currentLevel = level + 1; // start as 1
20
23
  const uuid = useId();
21
24
  const currentKey = id || title || href || uuid;
22
25
  const currentPath = useMemo(() => [...parentPath, currentKey], [parentPath, currentKey]);
23
- const { activatedPath, collapsed, currentPathname, filterText, handleCollapseChange, setActivatedPath, } = use(NavigationActivatedContext);
24
- useEffect(() => {
25
- if (currentPathname === href) {
26
- setActivatedPath(currentPath);
27
- setOpen(true);
28
- }
29
- // eslint-disable-next-line react-hooks/exhaustive-deps
30
- }, []);
31
- const Component = href ? 'a' : 'div';
26
+ const currentPathKey = currentPath.join('::');
27
+ const Component = href && !children
28
+ ? ((_a = anchorComponent !== null && anchorComponent !== void 0 ? anchorComponent : optionsAnchorComponent) !== null && _a !== void 0 ? _a : 'a')
29
+ : 'div';
32
30
  const flattenedChildren = useMemo(() => flattenChildren(children), [children]);
33
31
  const { badge, items } = useMemo(() => {
34
32
  let badgeComponent = null;
@@ -51,6 +49,13 @@ const NavigationOption = forwardRef((props, ref) => {
51
49
  });
52
50
  return { badge: badgeComponent, items };
53
51
  }, [flattenedChildren]);
52
+ // Default open if current path is activated
53
+ useEffect(() => {
54
+ if (activatedPathKey === currentPathKey ||
55
+ activatedPathKey.startsWith(`${currentPathKey}::`)) {
56
+ setOpen(true);
57
+ }
58
+ }, [activatedPathKey, currentLevel, currentPathKey]);
54
59
  const [filter, setFilter] = useState(true);
55
60
  useEffect(() => {
56
61
  var _a;
@@ -60,10 +65,28 @@ const NavigationOption = forwardRef((props, ref) => {
60
65
  }
61
66
  setFilter((_a = (title.includes(filterText) || (href === null || href === void 0 ? void 0 : href.includes(filterText)))) !== null && _a !== void 0 ? _a : false);
62
67
  }, [currentPath, filterText, href, title]);
68
+ const titleRef = useRef(null);
69
+ const [titleOverflow, setTitleOverflow] = useState(false);
70
+ useEffect(() => {
71
+ if (!titleRef.current)
72
+ return;
73
+ const checkOverflow = () => {
74
+ if (!titleRef.current)
75
+ return;
76
+ const { scrollWidth, clientWidth } = titleRef.current;
77
+ setTitleOverflow(scrollWidth > clientWidth);
78
+ };
79
+ checkOverflow();
80
+ const resizeObserver = new ResizeObserver(checkOverflow);
81
+ resizeObserver.observe(titleRef.current);
82
+ return () => {
83
+ resizeObserver.disconnect();
84
+ };
85
+ }, [title]);
63
86
  return (jsxs("li", { ...rest, ref: ref, className: cx(navigationOptionClasses.host, open && navigationOptionClasses.open, !children && navigationOptionClasses.basic, (active !== null && active !== void 0 ? active : (activatedPath === null || activatedPath === void 0 ? void 0 : activatedPath[currentLevel - 1]) === currentKey) &&
64
- navigationOptionClasses.active, collapsed && navigationOptionClasses.collapsed, !collapsed && !filter && navigationOptionClasses.hidden, className), "data-id": currentKey, children: [jsx(Tooltip, { options: {
65
- placement: 'right',
66
- }, title: collapsed ? title : undefined, children: ({ onMouseEnter, onMouseLeave, ref: tooltipChildRef }) => (jsxs(Component, { className: cx(navigationOptionClasses.content, navigationOptionClasses.level(currentLevel)), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ref: tooltipChildRef, href: href, onClick: () => {
87
+ navigationOptionClasses.active, collapsed && navigationOptionClasses.collapsed, !collapsed && !filter && navigationOptionClasses.hidden, className), "data-id": currentKey, children: [jsx(Tooltip, { disablePortal: false, options: {
88
+ placement: collapsed ? 'right' : 'top',
89
+ }, title: collapsed || titleOverflow ? title : undefined, children: ({ onMouseEnter, onMouseLeave, ref: tooltipChildRef }) => (jsxs(Component, { className: cx(navigationOptionClasses.content, navigationOptionClasses.level(currentLevel)), href: Component === 'div' ? undefined : href, onClick: () => {
67
90
  setOpen(!open);
68
91
  onTriggerClick === null || onTriggerClick === void 0 ? void 0 : onTriggerClick(currentPath, currentKey, href);
69
92
  if (collapsed) {
@@ -78,9 +101,7 @@ const NavigationOption = forwardRef((props, ref) => {
78
101
  if (!children)
79
102
  setActivatedPath(currentPath);
80
103
  }
81
- }, role: "menuitem", tabIndex: 0, children: [icon && jsx(Icon, { className: navigationOptionClasses.icon, icon: icon }), jsx("span", { className: navigationOptionClasses.title, children: title }), badge, children && (jsx(Icon, { className: navigationOptionClasses.toggleIcon, icon: GroupToggleIcon }))] })) }), children && !collapsed && (jsx(Collapse, { className: navigationOptionClasses.childrenWrapper, style: {
82
- width: '100%',
83
- }, in: !!open, children: jsx(NavigationOptionLevelContext.Provider, { value: {
104
+ }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ref: tooltipChildRef, role: "menuitem", tabIndex: 0, children: [icon && jsx(Icon, { className: navigationOptionClasses.icon, icon: icon }), jsx(Fade, { ref: titleRef, in: collapsed === false || !icon, children: jsx("span", { className: navigationOptionClasses.title, children: title }) }), badge, children && (jsx(Icon, { className: navigationOptionClasses.toggleIcon, icon: GroupToggleIcon }))] })) }), children && !collapsed && (jsx(Collapse, { lazyMount: true, className: cx(navigationOptionClasses.childrenWrapper), in: open, children: jsx(NavigationOptionLevelContext.Provider, { value: {
84
105
  level: currentLevel,
85
106
  path: currentPath,
86
107
  }, children: jsx("ul", { className: navigationOptionClasses.group, children: items }) }) }))] }));
@@ -11,22 +11,26 @@ import Icon from '../Icon/Icon.js';
11
11
  import cx from 'clsx';
12
12
 
13
13
  const NavigationOverflowMenuOption = forwardRef((props, ref) => {
14
- const { active, children, className, defaultOpen = false, href, icon, id, onTriggerClick, title, ...rest } = props;
14
+ var _a;
15
+ const { active, children, className, anchorComponent, defaultOpen = false, href, icon, id, onTriggerClick, title, ...rest } = props;
15
16
  const [open, setOpen] = useState(defaultOpen);
16
17
  const { level, path: parentPath } = use(NavigationOptionLevelContext);
17
18
  const currentLevel = level + 1; // start as 1
18
19
  const uuid = useId();
19
20
  const currentKey = id || title || href || uuid;
20
21
  const currentPath = useMemo(() => [...parentPath, currentKey], [parentPath, currentKey]);
21
- const { activatedPath, setActivatedPath, currentPathname } = use(NavigationActivatedContext);
22
+ const currentPathKey = currentPath.join('::');
23
+ const { activatedPath, activatedPathKey, setActivatedPath, optionsAnchorComponent, } = use(NavigationActivatedContext);
24
+ // Default open if current path is activated
22
25
  useEffect(() => {
23
- if (currentPathname === href) {
24
- setActivatedPath(currentPath);
26
+ if (activatedPathKey === currentPathKey ||
27
+ activatedPathKey.startsWith(`${currentPathKey}::`)) {
25
28
  setOpen(true);
26
29
  }
27
- // eslint-disable-next-line react-hooks/exhaustive-deps
28
- }, []);
29
- const Component = href ? 'a' : 'div';
30
+ }, [activatedPathKey, currentLevel, currentPathKey]);
31
+ const Component = href
32
+ ? ((_a = anchorComponent !== null && anchorComponent !== void 0 ? anchorComponent : optionsAnchorComponent) !== null && _a !== void 0 ? _a : 'a')
33
+ : 'div';
30
34
  const flattenedChildren = useMemo(() => flattenChildren(children), [children]);
31
35
  const { badge, items } = useMemo(() => {
32
36
  let badgeComponent = null;
@@ -3,6 +3,7 @@ import { DropdownProps } from '../Dropdown';
3
3
  export interface NavigationUserMenuProps extends Omit<DropdownProps, 'children' | 'type'> {
4
4
  children?: ReactNode;
5
5
  className?: string;
6
+ collapsedPlacement?: DropdownProps['placement'];
6
7
  imgSrc?: string;
7
8
  onClick?: () => void;
8
9
  }
@@ -1,26 +1,45 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { forwardRef, useState } from 'react';
2
+ import { forwardRef, useState, use, useRef, useEffect } from 'react';
3
3
  import { navigationUserMenuClasses } from '@mezzanine-ui/core/navigation';
4
4
  import { UserIcon, ChevronDownIcon } from '@mezzanine-ui/icons';
5
+ import { NavigationActivatedContext } from './context.js';
5
6
  import Dropdown from '../Dropdown/Dropdown.js';
7
+ import Tooltip from '../Tooltip/Tooltip.js';
6
8
  import Icon from '../Icon/Icon.js';
7
9
  import cx from 'clsx';
8
10
 
9
11
  const NavigationUserMenu = forwardRef((props, ref) => {
10
- // shared props
11
12
  const { children, className, imgSrc, onClick, ...rest } = props;
12
- const { open: openProp, onClose, placement = 'top-end', onVisibilityChange, ...dropdownRest } = rest;
13
+ const { open: openProp, onClose, placement = 'top-end', collapsedPlacement = 'right-end', onVisibilityChange, ...dropdownRest } = rest;
13
14
  const [imgError, setImgError] = useState(false);
14
15
  const [_open, setOpen] = useState(false);
16
+ const { collapsed } = use(NavigationActivatedContext);
15
17
  const open = openProp !== null && openProp !== void 0 ? openProp : _open;
16
- return (jsx(Dropdown, { ...dropdownRest, open: open, placement: placement, onVisibilityChange: () => {
18
+ const userNameRef = useRef(null);
19
+ const [userNameOverflow, setUserNameOverflow] = useState(false);
20
+ useEffect(() => {
21
+ if (!userNameRef.current)
22
+ return;
23
+ const resizeObserver = new ResizeObserver(() => {
24
+ if (userNameRef.current) {
25
+ setUserNameOverflow(userNameRef.current.scrollWidth > userNameRef.current.offsetWidth);
26
+ }
27
+ });
28
+ resizeObserver.observe(userNameRef.current);
29
+ return () => {
30
+ resizeObserver.disconnect();
31
+ };
32
+ }, []);
33
+ return (jsx(Dropdown, { ...dropdownRest, open: open, placement: collapsed ? collapsedPlacement : placement, onVisibilityChange: () => {
17
34
  setOpen(!open);
18
35
  onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(!open);
19
36
  onClick === null || onClick === void 0 ? void 0 : onClick();
20
37
  }, onClose: () => {
21
38
  setOpen(false);
22
39
  onClose === null || onClose === void 0 ? void 0 : onClose();
23
- }, children: jsxs("button", { type: "button", ref: ref, className: cx(navigationUserMenuClasses.host, open && navigationUserMenuClasses.open, className), children: [jsx("span", { className: navigationUserMenuClasses.avatar, children: imgError ? (jsx(Icon, { icon: UserIcon })) : (jsx("img", { alt: "User avatar", className: navigationUserMenuClasses.avatar, src: imgSrc, onError: () => setImgError(true) })) }), children && jsx("span", { className: navigationUserMenuClasses.userName, children: children }), jsx(Icon, { className: navigationUserMenuClasses.icon, icon: ChevronDownIcon })] }) }));
40
+ }, children: jsx("button", { className: cx(navigationUserMenuClasses.host, open && navigationUserMenuClasses.open, className), ref: ref, type: "button", children: jsx(Tooltip, { disablePortal: false, options: {
41
+ placement: collapsed ? 'right' : 'top',
42
+ }, title: (collapsed || userNameOverflow) && !open ? children : undefined, children: ({ onMouseEnter, onMouseLeave, ref: tooltipRef }) => (jsxs("span", { className: navigationUserMenuClasses.content, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ref: tooltipRef, children: [jsx("span", { className: navigationUserMenuClasses.avatar, children: imgError || !imgSrc ? (jsx(Icon, { icon: UserIcon })) : (jsx("img", { alt: "User avatar", className: navigationUserMenuClasses.avatar, src: imgSrc, onError: () => setImgError(true) })) }), children && (jsx("span", { className: navigationUserMenuClasses.userName, children: jsx("span", { ref: userNameRef, children: children }) })), jsx(Icon, { className: navigationUserMenuClasses.icon, icon: ChevronDownIcon })] })) }) }) }));
24
43
  });
25
44
 
26
45
  export { NavigationUserMenu as default };
@@ -8,9 +8,11 @@ export declare const NavigationOptionLevelContext: import("react").Context<{
8
8
  }>;
9
9
  export declare const NavigationActivatedContext: import("react").Context<{
10
10
  activatedPath: string[];
11
+ activatedPathKey: string;
11
12
  collapsed: boolean;
12
13
  currentPathname: string | null;
13
14
  filterText: string;
14
15
  handleCollapseChange: (newCollapsed: boolean) => void;
15
16
  setActivatedPath: (path: string[]) => void;
17
+ optionsAnchorComponent?: React.ElementType;
16
18
  }>;
@@ -1,6 +1,9 @@
1
1
  import { createContext } from 'react';
2
2
 
3
- const navigationOptionLevelContextDefaultValues = { level: 0, path: [] };
3
+ const navigationOptionLevelContextDefaultValues = {
4
+ level: 0,
5
+ path: [],
6
+ };
4
7
  const NavigationOptionLevelContext = createContext(navigationOptionLevelContextDefaultValues);
5
8
  const NavigationActivatedContext = createContext(null);
6
9
 
@@ -69,7 +69,7 @@ const RangePickerTrigger = forwardRef(function RangePickerTrigger(props, ref) {
69
69
  const handleToBlur = useCallback((e) => {
70
70
  onToBlur === null || onToBlur === void 0 ? void 0 : onToBlur(e);
71
71
  }, [onToBlur]);
72
- return (jsxs(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, className), clearable: !readOnly && clearable, suffix: suffix !== null && suffix !== void 0 ? suffix : defaultSuffix, children: [jsx(FormattedInput, { ...inputFromProps, ref: fromRef, "aria-disabled": disabled, "aria-label": "Start date", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesFrom, format: format, onBlur: handleFromBlur, onChange: handleFromChange, onFocus: handleFromFocus, placeholder: inputFromPlaceholder, readOnly: readOnly, required: required, validate: validateFrom, value: inputFromValue }), jsx(Icon, { icon: LongTailArrowRightIcon, className: pickerClasses.arrowIcon, "aria-hidden": "true" }), jsx(FormattedInput, { ...inputToProps, ref: toRef, "aria-disabled": disabled, "aria-label": "End date", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesTo, format: format, onBlur: handleToBlur, onChange: handleToChange, onFocus: handleToFocus, placeholder: inputToPlaceholder, readOnly: readOnly, required: required, validate: validateTo, value: inputToValue })] }));
72
+ return (jsxs(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, pickerClasses.hostRange, className), clearable: !readOnly && clearable, suffix: suffix !== null && suffix !== void 0 ? suffix : defaultSuffix, children: [jsx(FormattedInput, { ...inputFromProps, ref: fromRef, "aria-disabled": disabled, "aria-label": "Start date", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesFrom, format: format, onBlur: handleFromBlur, onChange: handleFromChange, onFocus: handleFromFocus, placeholder: inputFromPlaceholder, readOnly: readOnly, required: required, validate: validateFrom, value: inputFromValue }), jsx(Icon, { icon: LongTailArrowRightIcon, className: pickerClasses.arrowIcon, "aria-hidden": "true" }), jsx(FormattedInput, { ...inputToProps, ref: toRef, "aria-disabled": disabled, "aria-label": "End date", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesTo, format: format, onBlur: handleToBlur, onChange: handleToChange, onFocus: handleToFocus, placeholder: inputToPlaceholder, readOnly: readOnly, required: required, validate: validateTo, value: inputToValue })] }));
73
73
  });
74
74
 
75
75
  export { RangePickerTrigger as default };
@@ -1,4 +1,4 @@
1
- import { jsxs } from 'react/jsx-runtime';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef, cloneElement, isValidElement } from 'react';
3
3
  import { sectionClasses } from '@mezzanine-ui/core/section';
4
4
  import ContentHeader from '../ContentHeader/ContentHeader.js';
@@ -11,9 +11,9 @@ function getDisplayName(element) {
11
11
  if (typeof type === 'string') {
12
12
  return type;
13
13
  }
14
- return type.displayName
15
- || type.name
16
- || 'Unknown';
14
+ return (type.displayName ||
15
+ type.name ||
16
+ 'Unknown');
17
17
  }
18
18
  function isContentHeaderElement(element) {
19
19
  return isValidElement(element) && element.type === ContentHeader;
@@ -28,7 +28,7 @@ function isTabElement(element) {
28
28
  * The react component for `mezzanine` section.
29
29
  */
30
30
  const Section = forwardRef(function Section(props, ref) {
31
- const { children, className, contentHeader, filterArea, tab, } = props;
31
+ const { children, className, contentHeader, filterArea, tab } = props;
32
32
  let renderedContentHeader = null;
33
33
  let renderedFilterArea = null;
34
34
  let renderedTab = null;
@@ -56,7 +56,7 @@ const Section = forwardRef(function Section(props, ref) {
56
56
  console.warn(`[Section] Invalid tab type: <${getDisplayName(tab)}>. Only <Tab /> component from @mezzanine-ui/react is allowed.`);
57
57
  }
58
58
  }
59
- return (jsxs("div", { ref: ref, className: cx(sectionClasses.host, className), children: [renderedContentHeader, renderedFilterArea, renderedTab, children] }));
59
+ return (jsxs("div", { ref: ref, className: cx(sectionClasses.host, className), children: [renderedContentHeader, renderedFilterArea, renderedTab, jsx("div", { className: sectionClasses.hostContent, children: children })] }));
60
60
  });
61
61
 
62
62
  export { Section as default };
@@ -10,7 +10,8 @@ export interface CollapseProps extends TransitionImplementationProps, Omit<Nativ
10
10
  }
11
11
  /**
12
12
  * The react component for `mezzanine` transition collapse.
13
- * @deprecated 設計師未定義,暫時標記為 deprecated
13
+ * @deprecated 設計師未定義,暫時標記為 deprecated.
14
+ * 目前 NavigationOption 與 Accordion 正在使用此元件.
14
15
  */
15
16
  declare const Collapse: import("react").ForwardRefExoticComponent<CollapseProps & import("react").RefAttributes<HTMLElement>>;
16
17
  export default Collapse;
@@ -27,7 +27,8 @@ const defaultEasing = {
27
27
  };
28
28
  /**
29
29
  * The react component for `mezzanine` transition collapse.
30
- * @deprecated 設計師未定義,暫時標記為 deprecated
30
+ * @deprecated 設計師未定義,暫時標記為 deprecated.
31
+ * 目前 NavigationOption 與 Accordion 正在使用此元件.
31
32
  */
32
33
  const Collapse = forwardRef(function Collapse(props, ref) {
33
34
  const { appear, children, collapsedHeight: collapsedHeightProp = 0, delay = 0, duration = 'auto', easing = defaultEasing, in: inProp = false, lazyMount, keepMount, onEnter, onEntered, onEntering, onExit, onExiting, onExited, style, ...rest } = props;
package/Upload/Upload.js CHANGED
@@ -14,11 +14,13 @@ const Upload = forwardRef(function Upload(props, ref) {
14
14
  const { accept, className, disabled = false, mode = 'list', size = 'main', showFileSize = true, files: controlledFiles = [], onUpload, onDelete, onReload, onDownload, onZoomIn, onChange, id, name, multiple = false, maxFiles, hints, uploaderLabel, uploaderIcon, inputRef, inputProps, onMaxFilesExceeded, errorMessage, errorIcon, ...rest } = props;
15
15
  const files = controlledFiles;
16
16
  const filesRef = useRef(files);
17
+ const replaceFileIdRef = useRef(null);
18
+ const replaceInputRef = useRef(null);
17
19
  useEffect(() => {
18
20
  filesRef.current = files;
19
21
  }, [files]);
20
22
  // Default error icon when status is error and no errorIcon is provided
21
- const defaultErrorIconElement = useMemo(() => errorIcon !== null && errorIcon !== void 0 ? errorIcon : jsx(Icon, { icon: DangerousFilledIcon, color: "error", size: 24 }), [errorIcon]);
23
+ const defaultErrorIconElement = useMemo(() => errorIcon !== null && errorIcon !== void 0 ? errorIcon : (jsx(Icon, { icon: DangerousFilledIcon, color: "error", size: 24 })), [errorIcon]);
22
24
  // Auto-disable when maxFiles is reached
23
25
  const isMaxFilesReached = useMemo(() => {
24
26
  if (maxFiles === undefined)
@@ -37,6 +39,12 @@ const Upload = forwardRef(function Upload(props, ref) {
37
39
  const handleUpload = useCallback(async (selectedFiles) => {
38
40
  if (!selectedFiles.length)
39
41
  return;
42
+ // If a replace operation is in progress, remove the old file first
43
+ if (replaceFileIdRef.current !== null) {
44
+ const fileIdToReplace = replaceFileIdRef.current;
45
+ replaceFileIdRef.current = null;
46
+ filesRef.current = filesRef.current.filter((f) => f.id !== fileIdToReplace);
47
+ }
40
48
  // Check maxFiles limit
41
49
  if (maxFiles !== undefined) {
42
50
  const currentCount = filesRef.current.length;
@@ -100,7 +108,8 @@ const Upload = forwardRef(function Upload(props, ref) {
100
108
  var _a, _b, _c;
101
109
  const tempIndex = tempIdToIndex.get(file.id);
102
110
  // If this is a temp file and we have a corresponding backend file
103
- if (tempIndex !== undefined && tempIndex < backendFiles.length) {
111
+ if (tempIndex !== undefined &&
112
+ tempIndex < backendFiles.length) {
104
113
  const backendFile = backendFiles[tempIndex];
105
114
  // Replace temporary file with backend file (includes real ID and status)
106
115
  // Apply default error message and icon if status is error and not provided
@@ -124,7 +133,8 @@ const Upload = forwardRef(function Upload(props, ref) {
124
133
  const nextFiles = filesRef.current.map((file) => {
125
134
  const tempIndex = tempIdToIndex.get(file.id);
126
135
  // If this is a temp file and we have a corresponding backend ID
127
- if (tempIndex !== undefined && tempIndex < backendIds.length) {
136
+ if (tempIndex !== undefined &&
137
+ tempIndex < backendIds.length) {
128
138
  const backendId = backendIds[tempIndex];
129
139
  // Replace temporary ID with backend ID, set status to 'done'
130
140
  return {
@@ -142,7 +152,11 @@ const Upload = forwardRef(function Upload(props, ref) {
142
152
  else {
143
153
  // Old API: backward compatibility - no return value, assume success
144
154
  const nextFiles = filesRef.current.map((file) => tempFiles.some((tf) => tf.id === file.id)
145
- ? { ...file, status: 'done', progress: 100 }
155
+ ? {
156
+ ...file,
157
+ status: 'done',
158
+ progress: 100,
159
+ }
146
160
  : file);
147
161
  emitChange(nextFiles);
148
162
  }
@@ -172,7 +186,14 @@ const Upload = forwardRef(function Upload(props, ref) {
172
186
  : file);
173
187
  emitChange(nextFiles);
174
188
  }
175
- }, [emitChange, maxFiles, onMaxFilesExceeded, onUpload, errorMessage, defaultErrorIconElement]);
189
+ }, [
190
+ emitChange,
191
+ maxFiles,
192
+ onMaxFilesExceeded,
193
+ onUpload,
194
+ errorMessage,
195
+ defaultErrorIconElement,
196
+ ]);
176
197
  const handleDelete = useCallback((fileId) => {
177
198
  const file = findFileById(fileId);
178
199
  if (!file)
@@ -254,6 +275,7 @@ const Upload = forwardRef(function Upload(props, ref) {
254
275
  const shouldUsePictureCard = useMemo(() => {
255
276
  return /cards|card-wall/.test(mode);
256
277
  }, [mode]);
278
+ const isSingleFileCardMode = shouldUsePictureCard && maxFiles === 1;
257
279
  const renderUploadItem = useCallback((uploadFile) => {
258
280
  // Skip rendering if neither file nor url is provided
259
281
  if (!uploadFile.file && !uploadFile.url) {
@@ -262,18 +284,50 @@ const Upload = forwardRef(function Upload(props, ref) {
262
284
  // Determine if it's an image using shared utility
263
285
  const isImage = isImageFile(uploadFile.file, uploadFile.url);
264
286
  // For images, use 'thumbnail' to show image preview; for non-images, use 'icon' to show file icon
265
- const itemType = isImage ? 'thumbnail' : 'icon';
287
+ const itemType = isImage
288
+ ? 'thumbnail'
289
+ : 'icon';
266
290
  return (jsx(UploadItem, { file: uploadFile.file, url: uploadFile.url, id: uploadFile.id, status: uploadFile.status, size: size, type: itemType, showFileSize: showFileSize, disabled: disabled, onDelete: () => handleDelete(uploadFile.id), onDownload: () => handleDownload(uploadFile.id), onReload: () => handleReload(uploadFile.id) }, uploadFile.id));
267
- }, [size, showFileSize, disabled, handleDelete, handleDownload, handleReload]);
291
+ }, [
292
+ size,
293
+ showFileSize,
294
+ disabled,
295
+ handleDelete,
296
+ handleDownload,
297
+ handleReload,
298
+ ]);
268
299
  const uploaderElement = (jsx(Uploader, { accept: accept, disabled: effectiveDisabled, id: id, name: name, multiple: multiple, label: uploaderLabel, icon: uploaderIcon, inputRef: inputRef, inputProps: inputProps, hints: hints, onUpload: handleUpload, ...uploaderConfig }));
269
300
  const topUploaderElement = topUploaderConfig ? (jsx(Uploader, { accept: accept, disabled: effectiveDisabled, id: id ? `${id}-top` : undefined, name: name, multiple: multiple, label: uploaderLabel, icon: uploaderIcon, inputRef: inputRef, inputProps: inputProps, hints: hints, onUpload: handleUpload, ...topUploaderConfig })) : null;
270
301
  const hintsElement = useMemo(() => {
271
- if (!hints || hints.length === 0 || mode === 'list' || mode === 'card-wall')
302
+ if (!hints ||
303
+ hints.length === 0 ||
304
+ mode === 'list' ||
305
+ mode === 'card-wall')
272
306
  return null;
273
307
  const hintsClassName = mode === 'cards' ? uploadClasses.fillWidthHints : uploadClasses.hints;
274
308
  return (jsx("ul", { className: hintsClassName, children: hints.map((hint) => (jsxs("li", { className: uploadClasses.hint(hint.type || 'info'), children: [jsx(Icon, { icon: hint.type === 'info' ? InfoFilledIcon : DangerousFilledIcon, color: hint.type === 'info' ? 'info' : 'error', size: 14 }), hint.label] }, hint.label))) }));
275
309
  }, [hints, mode]);
276
- return (jsxs("div", { ref: ref, className: cx(uploadClasses.host, className, mode === 'cards' && uploadClasses.hostCards), ...rest, children: [topUploaderElement, !shouldUsePictureCard && (jsxs("div", { className: uploadClasses.uploadButtonList, children: [uploaderElement, mode === 'button-list' && hintsElement] })), jsxs("div", { className: cx(uploadClasses.uploadList, shouldUsePictureCard && uploadClasses.uploadListCards), children: [shouldUsePictureCard && (jsxs(Fragment, { children: [imageFiles.map((uploadFile) => (jsx(UploadPictureCard, { file: uploadFile.file, url: uploadFile.url, id: uploadFile.id, status: uploadFile.status, size: size, disabled: disabled, errorMessage: uploadFile.errorMessage, onDelete: () => handleDelete(uploadFile.id), onReload: () => handleReload(uploadFile.id), onDownload: () => handleDownload(uploadFile.id), onZoomIn: () => handleZoomIn(uploadFile.id) }, uploadFile.id))), uploaderElement] })), nonImageFiles.length > 0 && nonImageFiles.map(renderUploadItem), !shouldUsePictureCard && imageFiles.length > 0 && imageFiles.map(renderUploadItem)] }), mode === 'cards' && hintsElement] }));
310
+ return (jsxs("div", { ref: ref, className: cx(uploadClasses.host, className, mode === 'cards' && uploadClasses.hostCards), ...rest, children: [topUploaderElement, !shouldUsePictureCard && (jsxs("div", { className: uploadClasses.uploadButtonList, children: [uploaderElement, mode === 'button-list' && hintsElement] })), jsxs("div", { className: cx(uploadClasses.uploadList, shouldUsePictureCard && uploadClasses.uploadListCards), children: [shouldUsePictureCard && (jsxs(Fragment, { children: [imageFiles.map((uploadFile) => (jsx(UploadPictureCard, { file: uploadFile.file, url: uploadFile.url, id: uploadFile.id, status: uploadFile.status, size: size, disabled: disabled, errorMessage: uploadFile.errorMessage, onDelete: () => handleDelete(uploadFile.id), onReload: () => handleReload(uploadFile.id), ...(!isSingleFileCardMode && {
311
+ onDownload: () => handleDownload(uploadFile.id),
312
+ onZoomIn: () => handleZoomIn(uploadFile.id),
313
+ }), ...(isSingleFileCardMode && {
314
+ onReplace: (e) => {
315
+ var _a;
316
+ e.stopPropagation();
317
+ replaceFileIdRef.current = uploadFile.id;
318
+ (_a = replaceInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
319
+ },
320
+ }) }, uploadFile.id))), !isSingleFileCardMode && uploaderElement, isSingleFileCardMode &&
321
+ imageFiles.length === 0 &&
322
+ uploaderElement, isSingleFileCardMode && (jsx("input", { ref: replaceInputRef, accept: accept, style: { display: 'none' }, type: "file", onChange: (e) => {
323
+ var _a;
324
+ const selectedFiles = Array.from((_a = e.target.files) !== null && _a !== void 0 ? _a : []);
325
+ e.target.value = '';
326
+ if (selectedFiles.length)
327
+ handleUpload(selectedFiles);
328
+ } }))] })), nonImageFiles.length > 0 && nonImageFiles.map(renderUploadItem), !shouldUsePictureCard &&
329
+ imageFiles.length > 0 &&
330
+ imageFiles.map(renderUploadItem)] }), mode === 'cards' && hintsElement] }));
277
331
  });
278
332
 
279
333
  export { Upload as default };