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

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.
package/Badge/Badge.d.ts CHANGED
@@ -6,24 +6,28 @@ declare const Badge: import("react").ForwardRefExoticComponent<(Omit<Omit<Native
6
6
  children?: never;
7
7
  count: number;
8
8
  overflowCount?: number;
9
+ size?: never;
9
10
  text?: never;
10
11
  variant: BadgeCountVariant;
11
12
  }, "ref"> | Omit<Omit<NativeElementPropsWithoutKeyAndRef<"span">, "children"> & {
12
13
  children?: never;
13
14
  count?: never;
14
15
  overflowCount?: never;
16
+ size?: import("@mezzanine-ui/core/badge").BadgeTextSize;
15
17
  text?: string;
16
18
  variant: import("@mezzanine-ui/core/badge").BadgeDotVariant;
17
19
  }, "ref"> | Omit<Omit<NativeElementPropsWithoutKeyAndRef<"span">, "children"> & {
18
20
  children?: import("react").ReactNode;
19
21
  count?: never;
20
22
  overflowCount?: never;
23
+ size?: never;
21
24
  text?: never;
22
25
  variant: import("@mezzanine-ui/core/badge").BadgeDotVariant;
23
26
  }, "ref"> | Omit<Omit<NativeElementPropsWithoutKeyAndRef<"span">, "children"> & {
24
27
  children?: never;
25
28
  count?: never;
26
29
  overflowCount?: never;
30
+ size?: import("@mezzanine-ui/core/badge").BadgeTextSize;
27
31
  text: string;
28
32
  variant: import("@mezzanine-ui/core/badge").BadgeTextVariant;
29
33
  }, "ref">) & import("react").RefAttributes<HTMLSpanElement>>;
package/Badge/Badge.js CHANGED
@@ -14,8 +14,8 @@ const isCountVariant = (variant) => [
14
14
  * The react component for `mezzanine` badge.
15
15
  */
16
16
  const Badge = forwardRef(function Badge(props, ref) {
17
- const { children, count, className, overflowCount, text, variant, ...rest } = props;
18
- return (jsxs("div", { className: badgeClasses.container(!!children), children: [children, jsx("span", { ...rest, ref: ref, className: cx(badgeClasses.host, badgeClasses.variant(variant), { [badgeClasses.hide]: isCountVariant(variant) && count === 0 }, className), children: isCountVariant(variant)
17
+ const { children, count, className, overflowCount, size, text, variant, ...rest } = props;
18
+ return (jsxs("div", { className: badgeClasses.container(!!children), children: [children, jsx("span", { ...rest, ref: ref, className: cx(badgeClasses.host, badgeClasses.variant(variant), { [badgeClasses.hide]: isCountVariant(variant) && count === 0 }, size && badgeClasses.size(size), className), children: isCountVariant(variant)
19
19
  ? overflowCount && count > overflowCount
20
20
  ? `${overflowCount}+`
21
21
  : count
@@ -1,4 +1,4 @@
1
- import { BadgeCountVariant, BadgeDotVariant, BadgeTextVariant } from '@mezzanine-ui/core/badge';
1
+ import { BadgeCountVariant, BadgeDotVariant, BadgeTextSize, BadgeTextVariant } from '@mezzanine-ui/core/badge';
2
2
  import { ReactNode } from 'react';
3
3
  import { NativeElementPropsWithoutKeyAndRef } from 'react/src/utils/jsx-types';
4
4
  export type BadgeProps = Omit<NativeElementPropsWithoutKeyAndRef<'span'>, 'children'> & BadgeVariantProps;
@@ -21,6 +21,11 @@ type BadgeCountProps = {
21
21
  * it will show overflowCount suffixed with a "+".
22
22
  */
23
23
  overflowCount?: number;
24
+ /**
25
+ * ONLY AVAILABLE FOR DOT WITH TEXT BADGE.
26
+ * Controls the size of the dot and text.
27
+ */
28
+ size?: never;
24
29
  /**
25
30
  * ONLY AVAILABLE FOR DOT WITH TEXT BADGE.
26
31
  * String displayed next to the dot badge.
@@ -35,6 +40,7 @@ type BadgeTextProps = {
35
40
  children?: never;
36
41
  count?: never;
37
42
  overflowCount?: never;
43
+ size?: BadgeTextSize;
38
44
  text: string;
39
45
  variant: BadgeTextVariant;
40
46
  };
@@ -42,6 +48,11 @@ type BadgeDotWithTextProps = {
42
48
  children?: never;
43
49
  count?: never;
44
50
  overflowCount?: never;
51
+ /**
52
+ * Controls the size of the text.
53
+ * @default 'main'
54
+ */
55
+ size?: BadgeTextSize;
45
56
  text?: string;
46
57
  variant: BadgeDotVariant;
47
58
  };
@@ -49,6 +60,7 @@ type BadgeDotProps = {
49
60
  children?: ReactNode;
50
61
  count?: never;
51
62
  overflowCount?: never;
63
+ size?: never;
52
64
  text?: never;
53
65
  variant: BadgeDotVariant;
54
66
  };
@@ -14,10 +14,11 @@ import cx from 'clsx';
14
14
  * You may use it to compose your own calendar.
15
15
  */
16
16
  function CalendarDays(props) {
17
- const { locale, getCalendarGrid, getDate, getMonth, getNow, isDateIncluded, isSameDate, setDate, setMonth, setHour, setMinute, setSecond, setMillisecond, } = useCalendarContext();
17
+ const { locale, getCalendarGrid, getDate, getMonth, getNow, getWeekends, isDateIncluded, isSameDate, setDate, setMonth, setHour, setMinute, setSecond, setMillisecond, } = useCalendarContext();
18
18
  const { className, displayWeekDayLocale = locale, isYearDisabled, isMonthDisabled, isDateDisabled, isDateInRange, onClick: onClickProp, onDateHover, renderAnnotations, referenceDate, value, ...rest } = props;
19
+ const weekends = useMemo(() => getWeekends(displayWeekDayLocale), [getWeekends, displayWeekDayLocale]);
19
20
  const daysGrid = useMemo(() => getCalendarGrid(referenceDate, displayWeekDayLocale), [getCalendarGrid, displayWeekDayLocale, referenceDate]);
20
- return (jsx("div", { ...rest, className: cx(calendarClasses.board, className), children: jsxs("div", { className: calendarClasses.daysGrid, children: [jsx(CalendarDayOfWeek, { displayWeekDayLocale: displayWeekDayLocale }), daysGrid.map((week, index) => (jsx("div", { className: calendarClasses.row, children: week.map((dateNum) => {
21
+ return (jsx("div", { ...rest, className: cx(calendarClasses.board, className), children: jsxs("div", { className: calendarClasses.daysGrid, children: [jsx(CalendarDayOfWeek, { displayWeekDayLocale: displayWeekDayLocale }), daysGrid.map((week, index) => (jsx("div", { className: calendarClasses.row, children: week.map((dateNum, dayIndex) => {
21
22
  const isPrevMonth = index === 0 && dateNum > 7;
22
23
  const isNextMonth = index > 3 && dateNum <= 14;
23
24
  const thisMonth = getMonth(referenceDate);
@@ -66,7 +67,7 @@ function CalendarDays(props) {
66
67
  ]
67
68
  .filter(Boolean)
68
69
  .join(', ');
69
- return (jsx(CalendarCell, { mode: "day", today: isSameDate(date, getNow()), active: active, disabled: isPrevMonth || isNextMonth, withAnnotation: Boolean(renderAnnotations), isRangeStart: inRangeStart, isRangeEnd: inRangeEnd, children: jsxs("button", { type: "button", "aria-disabled": disabled, disabled: disabled, "aria-label": ariaLabel, "aria-pressed": active, "aria-current": isToday ? 'date' : undefined, onMouseEnter: onMouseEnter, className: cx(calendarClasses.button, {
70
+ return (jsx(CalendarCell, { active: active, disabled: isPrevMonth || isNextMonth, isRangeEnd: inRangeEnd, isRangeStart: inRangeStart, isWeekend: weekends[dayIndex], mode: "day", today: isSameDate(date, getNow()), withAnnotation: Boolean(renderAnnotations), children: jsxs("button", { type: "button", "aria-disabled": disabled, disabled: disabled, "aria-label": ariaLabel, "aria-pressed": active, "aria-current": isToday ? 'date' : undefined, onMouseEnter: onMouseEnter, className: cx(calendarClasses.button, {
70
71
  [calendarClasses.buttonInRange]: inRange,
71
72
  [calendarClasses.buttonActive]: active,
72
73
  [calendarClasses.buttonDisabled]: disabled,
@@ -13,8 +13,9 @@ import cx from 'clsx';
13
13
  * You may use it to compose your own calendar.
14
14
  */
15
15
  function CalendarWeeks(props) {
16
- const { locale, getCalendarGrid, getWeek, getDate, getMonth, getNow, isInMonth, isSameDate, isWeekIncluded, setDate, setMonth, setHour, setMinute, setSecond, setMillisecond, getCurrentWeekFirstDate, } = useCalendarContext();
16
+ const { locale, getCalendarGrid, getWeek, getDate, getMonth, getNow, getWeekends, isInMonth, isSameDate, isWeekIncluded, setDate, setMonth, setHour, setMinute, setSecond, setMillisecond, getCurrentWeekFirstDate, } = useCalendarContext();
17
17
  const { className, displayWeekDayLocale = locale, isYearDisabled, isMonthDisabled, isWeekDisabled, isWeekInRange, onClick: onClickProp, onWeekHover, referenceDate, value, ...rest } = props;
18
+ const weekends = useMemo(() => getWeekends(displayWeekDayLocale), [getWeekends, displayWeekDayLocale]);
18
19
  const daysGrid = useMemo(() => getCalendarGrid(referenceDate, displayWeekDayLocale), [getCalendarGrid, referenceDate, displayWeekDayLocale]);
19
20
  // Pre-calculate all weeks data including dates and week first dates
20
21
  const weeksData = useMemo(() => {
@@ -143,8 +144,8 @@ function CalendarWeeks(props) {
143
144
  isSameDate(currentDate, lastWeekDatesMap.lastWeekDates[6]);
144
145
  cellActive = isFirstWeekFirstDate || isLastWeekLastDate;
145
146
  }
146
- return (jsx(CalendarCell, { mode: "week", today: isSameDate(dates[dateIndex], getNow()), disabled: disabled ||
147
- !isInMonth(dates[dateIndex], getMonth(referenceDate)), active: cellActive, isRangeStart: isFirstWeekFirstDate, isRangeEnd: isLastWeekLastDate, children: jsx("div", { className: cx(calendarClasses.button, {
147
+ return (jsx(CalendarCell, { active: cellActive, disabled: disabled ||
148
+ !isInMonth(dates[dateIndex], getMonth(referenceDate)), isRangeEnd: isLastWeekLastDate, isRangeStart: isFirstWeekFirstDate, isWeekend: weekends[dateIndex], mode: "week", today: isSameDate(dates[dateIndex], getNow()), children: jsx("div", { className: cx(calendarClasses.button, {
148
149
  [calendarClasses.buttonInRange]: weekIncluded,
149
150
  [calendarClasses.buttonActive]: cellActive,
150
151
  }), style: {
@@ -1,5 +1,5 @@
1
1
  import { ReactElement } from 'react';
2
- import { DescriptionOrientation } from '@mezzanine-ui/core/description';
2
+ import { DescriptionOrientation, DescriptionSize } from '@mezzanine-ui/core/description';
3
3
  import { DescriptionTitleProps } from './DescriptionTitle';
4
4
  import { DescriptionContentProps } from './DescriptionContent';
5
5
  import { BadgeProps } from '../Badge/typings';
@@ -21,6 +21,11 @@ export type DescriptionProps = DistributiveOmit<DescriptionTitleProps, 'classNam
21
21
  * @default 'horizontal'
22
22
  */
23
23
  orientation?: DescriptionOrientation;
24
+ /**
25
+ * Controls the text size of the description content
26
+ * @default 'main'
27
+ */
28
+ size?: DescriptionSize;
24
29
  /**
25
30
  * title text for description
26
31
  */
@@ -1,13 +1,20 @@
1
1
  'use client';
2
- import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { forwardRef } from 'react';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { forwardRef, isValidElement, cloneElement } from 'react';
4
4
  import { descriptionClasses } from '@mezzanine-ui/core/description';
5
5
  import DescriptionTitle from './DescriptionTitle.js';
6
+ import { DescriptionContext } from './DescriptionContext.js';
6
7
  import cx from 'clsx';
7
8
 
8
9
  const Description = forwardRef(function Description(props, ref) {
9
- const { children, className, orientation = 'horizontal', title, ...rest } = props;
10
- return (jsxs("div", { className: cx(descriptionClasses.host, descriptionClasses.orientation(orientation), className), ref: ref, children: [jsx(DescriptionTitle, { ...rest, children: title }), children] }));
10
+ var _a;
11
+ const { children, className, orientation = 'horizontal', size = 'main', title, ...rest } = props;
12
+ const injectedChildren = isValidElement(children)
13
+ ? cloneElement(children, {
14
+ size: (_a = children.props.size) !== null && _a !== void 0 ? _a : size,
15
+ })
16
+ : children;
17
+ return (jsx(DescriptionContext.Provider, { value: { size }, children: jsxs("div", { className: cx(descriptionClasses.host, descriptionClasses.orientation(orientation), className), ref: ref, children: [jsx(DescriptionTitle, { ...rest, children: title }), injectedChildren] }) }));
11
18
  });
12
19
 
13
20
  export { Description as default };
@@ -1,5 +1,5 @@
1
1
  import { IconDefinition } from '@mezzanine-ui/icons';
2
- import { DescriptionSize, DescriptionContentVariant } from '@mezzanine-ui/core/description';
2
+ import { DescriptionContentVariant, DescriptionSize } from '@mezzanine-ui/core/description';
3
3
  interface DescriptionContentBaseProps {
4
4
  /**
5
5
  * Custom class name for content
@@ -10,8 +10,9 @@ interface DescriptionContentBaseProps {
10
10
  */
11
11
  children: string;
12
12
  /**
13
- * Control the text size of the content
14
- * @default 'main'
13
+ * Controls the text size of the content. When provided, overrides the size
14
+ * inherited from a parent <Description> component.
15
+ * @default context value or 'main'
15
16
  */
16
17
  size?: DescriptionSize;
17
18
  /**
@@ -31,6 +32,11 @@ interface DescriptionContentBaseProps {
31
32
  interface DescriptionContentWithClickableIcon {
32
33
  className?: string;
33
34
  children: string;
35
+ /**
36
+ * Controls the text size of the content. When provided, overrides the size
37
+ * inherited from a parent <Description> component.
38
+ * @default context value or 'main'
39
+ */
34
40
  size?: DescriptionSize;
35
41
  variant: Extract<DescriptionContentVariant, 'with-icon'>;
36
42
  icon: IconDefinition;
@@ -3,11 +3,14 @@ import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { forwardRef } from 'react';
4
4
  import { CaretUpIcon, CaretDownIcon } from '@mezzanine-ui/icons';
5
5
  import { descriptionClasses } from '@mezzanine-ui/core/description';
6
+ import { useDescriptionContext } from './DescriptionContext.js';
6
7
  import Icon from '../Icon/Icon.js';
7
8
  import cx from 'clsx';
8
9
 
9
10
  const DescriptionContent = forwardRef(function DescriptionContent(props, ref) {
10
- const { className, children, icon, onClickIcon, size = 'main', variant = 'normal', } = props;
11
+ const { className, children, icon, onClickIcon, size: sizeProp, variant = 'normal', } = props;
12
+ const { size: contextSize } = useDescriptionContext();
13
+ const size = sizeProp !== null && sizeProp !== void 0 ? sizeProp : contextSize;
11
14
  return (jsxs("span", { className: cx(descriptionClasses.contentHost, descriptionClasses.contentVariant(variant), descriptionClasses.contentSize(size), className), ref: ref, children: [variant === 'trend-up' && (jsx(Icon, { className: descriptionClasses.contentTrendUp, icon: CaretUpIcon, size: 16 })), variant === 'trend-down' && (jsx(Icon, { className: descriptionClasses.contentTrendDown, icon: CaretDownIcon, size: 16 })), children, variant === 'with-icon' && icon && (jsx(Icon, { className: descriptionClasses.contentIcon, icon: icon, size: 16, onClick: onClickIcon }))] }));
12
15
  });
13
16
 
@@ -0,0 +1,6 @@
1
+ import { DescriptionSize } from '@mezzanine-ui/core/description';
2
+ export interface DescriptionContextValue {
3
+ size: DescriptionSize;
4
+ }
5
+ export declare const DescriptionContext: import("react").Context<DescriptionContextValue>;
6
+ export declare const useDescriptionContext: () => DescriptionContextValue;
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import { createContext, useContext } from 'react';
3
+
4
+ const DescriptionContext = createContext({
5
+ size: 'main',
6
+ });
7
+ const useDescriptionContext = () => useContext(DescriptionContext);
8
+
9
+ export { DescriptionContext, useDescriptionContext };
@@ -6,3 +6,5 @@ export { default as DescriptionContent } from './DescriptionContent';
6
6
  export type { DescriptionContentProps } from './DescriptionContent';
7
7
  export { default as DescriptionGroup } from './DescriptionGroup';
8
8
  export type { DescriptionGroupProps } from './DescriptionGroup';
9
+ export { DescriptionContext } from './DescriptionContext';
10
+ export type { DescriptionContextValue } from './DescriptionContext';
@@ -2,3 +2,4 @@ export { default as Description } from './Description.js';
2
2
  export { default as DescriptionTitle } from './DescriptionTitle.js';
3
3
  export { default as DescriptionContent } from './DescriptionContent.js';
4
4
  export { default as DescriptionGroup } from './DescriptionGroup.js';
5
+ export { DescriptionContext } from './DescriptionContext.js';
@@ -37,6 +37,12 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
37
37
  * The icon to display alongside the hint text.
38
38
  */
39
39
  hintTextIcon?: IconDefinition;
40
+ /**
41
+ * Whether to display the hint text icon.
42
+ * When false, neither the custom icon nor the default severity icon will be shown.
43
+ * @default true
44
+ */
45
+ showHintTextIcon?: boolean;
40
46
  /**
41
47
  * The label text for the form field.
42
48
  */
package/Form/FormField.js CHANGED
@@ -10,7 +10,7 @@ import cx from 'clsx';
10
10
  * The React component for `mezzanine` form field.
11
11
  */
12
12
  const FormField = forwardRef(function FormField(props, ref) {
13
- const { children, className, counter, counterColor, 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;
13
+ const { children, className, counter, counterColor, controlFieldSlotLayout = ControlFieldSlotLayout.MAIN, density, disabled = false, fullWidth = false, hintText, hintTextIcon, showHintTextIcon, 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,
@@ -30,7 +30,7 @@ const FormField = forwardRef(function FormField(props, ref) {
30
30
  [formFieldClasses.fullWidth]: fullWidth,
31
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, {
32
32
  [formFieldClasses.hintTextAndCounterArea + '--align-right']: !(hintText || hintTextIcon) && counter,
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] })] }) }));
33
+ }), children: [(hintText || hintTextIcon) && (jsx(FormHintText, { hintText: hintText, hintTextIcon: hintTextIcon, severity: severity, showHintTextIcon: showHintTextIcon })), counter && (jsx("span", { className: cx(formFieldClasses.counter, formFieldClasses.counterColor(counterColor || FormFieldCounterColor.INFO)), children: counter }))] })) : null] })] }) }));
34
34
  });
35
35
 
36
36
  export { FormField as default };
@@ -17,6 +17,12 @@ export type FormHintTextProps = NativeElementPropsWithoutKeyAndRef<'span'> & {
17
17
  * if not provided, no icon will be displayed.
18
18
  */
19
19
  severity?: keyof typeof formHintIcons | undefined;
20
+ /**
21
+ * Whether to display the hint text icon.
22
+ * When false, neither the custom icon nor the default severity icon will be shown.
23
+ * @default true
24
+ */
25
+ showHintTextIcon?: boolean;
20
26
  };
21
27
  /**
22
28
  * The React component for `mezzanine` form message.
@@ -37,5 +43,11 @@ declare const FormHintText: import("react").ForwardRefExoticComponent<NativeElem
37
43
  * if not provided, no icon will be displayed.
38
44
  */
39
45
  severity?: keyof typeof formHintIcons | undefined;
46
+ /**
47
+ * Whether to display the hint text icon.
48
+ * When false, neither the custom icon nor the default severity icon will be shown.
49
+ * @default true
50
+ */
51
+ showHintTextIcon?: boolean;
40
52
  } & import("react").RefAttributes<HTMLSpanElement>>;
41
53
  export default FormHintText;
@@ -9,9 +9,10 @@ import cx from 'clsx';
9
9
  * The React component for `mezzanine` form message.
10
10
  */
11
11
  const FormHintText = forwardRef(function FormHintText(props, ref) {
12
- const { className, hintText, hintTextIcon, severity = 'info', ...rest } = props;
12
+ const { className, hintText, hintTextIcon, severity = 'info', showHintTextIcon = true, ...rest } = props;
13
13
  const defaultIcon = severity ? formHintIcons[severity] : null;
14
- return (jsxs("span", { ...rest, ref: ref, className: cx(formFieldClasses.hintText, severity ? formFieldClasses.hintTextSeverity(severity) : undefined, className), children: [hintTextIcon ? (jsx(Icon, { className: formFieldClasses.hintTextIcon, icon: hintTextIcon, color: severity })) : (defaultIcon && (jsx(Icon, { className: formFieldClasses.hintTextIcon, icon: defaultIcon, color: severity }))), hintText] }));
14
+ return (jsxs("span", { ...rest, ref: ref, className: cx(formFieldClasses.hintText, severity ? formFieldClasses.hintTextSeverity(severity) : undefined, className), children: [showHintTextIcon &&
15
+ (hintTextIcon ? (jsx(Icon, { className: formFieldClasses.hintTextIcon, icon: hintTextIcon, color: severity })) : (defaultIcon && (jsx(Icon, { className: formFieldClasses.hintTextIcon, icon: defaultIcon, color: severity })))), hintText] }));
15
16
  });
16
17
 
17
18
  export { FormHintText as default };
@@ -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 };
@@ -9,30 +9,35 @@ export interface UploadPictureCardAriaLabels {
9
9
  */
10
10
  cancelUpload?: string;
11
11
  /**
12
- * Aria label for uploading status.
13
- * @default 'Uploading'
12
+ * Aria label for the click-to-replace overlay label.
13
+ * @default 'Click to Replace'
14
14
  */
15
- uploading?: string;
15
+ clickToReplace?: string;
16
16
  /**
17
- * Aria label for zoom in button.
18
- * @default 'Zoom in image'
17
+ * Aria label for delete button.
18
+ * @default 'Delete file'
19
19
  */
20
- zoomIn?: string;
20
+ delete?: string;
21
21
  /**
22
22
  * Aria label for download button.
23
23
  * @default 'Download file'
24
24
  */
25
25
  download?: string;
26
- /**
27
- * Aria label for delete button.
28
- * @default 'Delete file'
29
- */
30
- delete?: string;
31
26
  /**
32
27
  * Aria label for reload/retry button.
33
28
  * @default 'Retry upload'
34
29
  */
35
30
  reload?: string;
31
+ /**
32
+ * Aria label for uploading status.
33
+ * @default 'Uploading'
34
+ */
35
+ uploading?: string;
36
+ /**
37
+ * Aria label for zoom in button.
38
+ * @default 'Zoom in image'
39
+ */
40
+ zoomIn?: string;
36
41
  }
37
42
  export interface UploadPictureCardProps extends NativeElementPropsWithoutKeyAndRef<'div'> {
38
43
  /**
@@ -90,10 +95,6 @@ export interface UploadPictureCardProps extends NativeElementPropsWithoutKeyAndR
90
95
  * When delete icon is clicked, this callback will be fired.
91
96
  */
92
97
  onDelete?: MouseEventHandler;
93
- /**
94
- * When zoom in icon is clicked, this callback will be fired.
95
- */
96
- onZoomIn?: MouseEventHandler;
97
98
  /**
98
99
  * When download icon is clicked, this callback will be fired.
99
100
  */
@@ -102,6 +103,15 @@ export interface UploadPictureCardProps extends NativeElementPropsWithoutKeyAndR
102
103
  * When reload icon is clicked, this callback will be fired.
103
104
  */
104
105
  onReload?: MouseEventHandler;
106
+ /**
107
+ * When provided, the card becomes a replacement trigger in done status.
108
+ * On hover, shows a "Click to Replace" overlay label. Fired when the card body is clicked.
109
+ */
110
+ onReplace?: MouseEventHandler;
111
+ /**
112
+ * When zoom in icon is clicked, this callback will be fired.
113
+ */
114
+ onZoomIn?: MouseEventHandler;
105
115
  }
106
116
  /**
107
117
  * The react component for `mezzanine` upload picture card.
@@ -15,14 +15,15 @@ import cx from 'clsx';
15
15
  */
16
16
  const UploadPictureCard = forwardRef(function UploadPictureCard(props, ref) {
17
17
  var _a;
18
- const { ariaLabels, className, file, url, status = 'loading', imageFit = 'cover', size = 'main', disabled = false, errorMessage, errorIcon, onDelete, onZoomIn, onDownload, onReload, ...rest } = props;
18
+ const { ariaLabels, className, file, url, status = 'loading', imageFit = 'cover', size = 'main', disabled = false, errorMessage, errorIcon, onDelete, onDownload, onReload, onReplace, onZoomIn, ...rest } = props;
19
19
  const defaultAriaLabels = {
20
20
  cancelUpload: 'Cancel upload',
21
- uploading: 'Uploading',
22
- zoomIn: 'Zoom in image',
23
- download: 'Download file',
21
+ clickToReplace: 'Click to Replace',
24
22
  delete: 'Delete file',
23
+ download: 'Download file',
25
24
  reload: 'Retry upload',
25
+ uploading: 'Uploading',
26
+ zoomIn: 'Zoom in image',
26
27
  };
27
28
  const labels = { ...defaultAriaLabels, ...ariaLabels };
28
29
  const isImage = useMemo(() => {
@@ -92,10 +93,17 @@ const UploadPictureCard = forwardRef(function UploadPictureCard(props, ref) {
92
93
  console.warn('UploadPictureCard: minor size is not supported for non-image files');
93
94
  return null;
94
95
  }
95
- return (jsx("div", { className: cx(uploadPictureCardClasses.host, uploadPictureCardClasses.size(size), disabled && uploadPictureCardClasses.disabled, className), "aria-disabled": disabled, ref: ref, role: "group", tabIndex: disabled ? -1 : 0, ...rest, children: jsxs("div", { className: uploadPictureCardClasses.container, children: [isImage && imageUrl && status !== 'error' && (jsx("img", { alt: fileName, src: imageUrl, style: {
96
+ return (jsx("div", { "aria-disabled": disabled, className: cx(uploadPictureCardClasses.host, uploadPictureCardClasses.size(size), disabled && uploadPictureCardClasses.disabled, onReplace && status === 'done' && uploadPictureCardClasses.replaceMode, className), onClick: onReplace && status === 'done' ? onReplace : undefined, onKeyDown: onReplace && status === 'done'
97
+ ? (e) => {
98
+ if (e.key === 'Enter' || e.key === ' ') {
99
+ e.preventDefault();
100
+ e.currentTarget.click();
101
+ }
102
+ }
103
+ : undefined, ref: ref, role: "group", tabIndex: disabled ? -1 : 0, ...rest, children: jsxs("div", { className: uploadPictureCardClasses.container, children: [isImage && imageUrl && status !== 'error' && (jsx("img", { alt: fileName, src: imageUrl, style: {
96
104
  objectFit: imageFit,
97
105
  objectPosition: 'center',
98
- } })), status === 'done' && size !== 'minor' && !isImage && (jsxs("div", { className: uploadPictureCardClasses.content, children: [jsx(Icon, { icon: FileIcon, color: "brand", size: 16 }), jsx(Typography, { className: uploadPictureCardClasses.name, ellipsis: true, children: fileName })] })), status === 'error' && size !== 'minor' && (jsxs("div", { className: uploadPictureCardClasses.errorMessage, role: "alert", "aria-live": "polite", children: [jsx(Icon, { icon: errorIconContent, color: "error", size: 16 }), jsx(Typography, { className: uploadPictureCardClasses.errorMessageText, children: errorMessageContent })] })), jsxs("div", { className: cx(uploadPictureCardClasses.actions, uploadPictureCardClasses.actionsStatus(status)), children: [status === 'loading' && size !== 'minor' && (jsxs(Fragment, { children: [jsx(ClearActions, { type: "embedded", variant: "contrast", onClick: onDelete, className: uploadPictureCardClasses.clearActionsIcon, "aria-label": labels.cancelUpload }), jsx("div", { className: uploadPictureCardClasses.loadingIcon, "aria-label": labels.uploading, children: jsx(Icon, { icon: SpinnerIcon, color: "fixed-light", spin: true, size: 32 }) })] })), status === 'done' && size !== 'minor' && (jsx(Fragment, { children: jsx("div", { className: uploadPictureCardClasses.tools, children: jsxs("div", { className: uploadPictureCardClasses.toolsContent, children: [jsx(Button, { variant: "base-secondary", size: "minor", icon: ZoomInIcon, iconType: "icon-only", onClick: onZoomIn, "aria-label": labels.zoomIn }), jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: DownloadIcon, onClick: onDownload, "aria-label": labels.download }), jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: TrashIcon, onClick: onDelete, "aria-label": labels.delete })] }) }) })), status === 'error' && size !== 'minor' && (jsx(Fragment, { children: jsx("div", { className: uploadPictureCardClasses.tools, children: jsxs("div", { className: uploadPictureCardClasses.toolsContent, children: [jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: ResetIcon, onClick: onReload, "aria-label": labels.reload }), jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: TrashIcon, onClick: onDelete, "aria-label": labels.delete })] }) }) })), size === 'minor' && (jsx(Icon, { icon: ZoomInIcon, color: "fixed-light", size: 24 }))] })] }) }));
106
+ } })), status === 'done' && size !== 'minor' && !isImage && (jsxs("div", { className: uploadPictureCardClasses.content, children: [jsx(Icon, { icon: FileIcon, color: "brand", size: 16 }), jsx(Typography, { className: uploadPictureCardClasses.name, ellipsis: true, children: fileName })] })), status === 'error' && size !== 'minor' && (jsxs("div", { className: uploadPictureCardClasses.errorMessage, role: "alert", "aria-live": "polite", children: [jsx(Icon, { icon: errorIconContent, color: "error", size: 16 }), jsx(Typography, { className: uploadPictureCardClasses.errorMessageText, children: errorMessageContent })] })), jsxs("div", { className: cx(uploadPictureCardClasses.actions, uploadPictureCardClasses.actionsStatus(status)), children: [status === 'loading' && size !== 'minor' && (jsxs(Fragment, { children: [jsx(ClearActions, { type: "embedded", variant: "contrast", onClick: onDelete, className: uploadPictureCardClasses.clearActionsIcon, "aria-label": labels.cancelUpload }), jsx("div", { className: uploadPictureCardClasses.loadingIcon, "aria-label": labels.uploading, children: jsx(Icon, { icon: SpinnerIcon, color: "fixed-light", spin: true, size: 32 }) })] })), status === 'done' && size !== 'minor' && (jsxs(Fragment, { children: [jsx("div", { className: uploadPictureCardClasses.tools, children: jsxs("div", { className: uploadPictureCardClasses.toolsContent, children: [onZoomIn && (jsx(Button, { variant: "base-secondary", size: "minor", icon: ZoomInIcon, iconType: "icon-only", onClick: onZoomIn, "aria-label": labels.zoomIn })), onDownload && (jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: DownloadIcon, onClick: onDownload, "aria-label": labels.download })), jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: TrashIcon, onClick: onDelete, "aria-label": labels.delete })] }) }), onReplace && (jsx("span", { className: uploadPictureCardClasses.replaceLabel, children: labels.clickToReplace }))] })), status === 'error' && size !== 'minor' && (jsx(Fragment, { children: jsx("div", { className: uploadPictureCardClasses.tools, children: jsxs("div", { className: uploadPictureCardClasses.toolsContent, children: [jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: ResetIcon, onClick: onReload, "aria-label": labels.reload }), jsx(Button, { variant: "base-secondary", size: "minor", iconType: "icon-only", icon: TrashIcon, onClick: onDelete, "aria-label": labels.delete })] }) }) })), size === 'minor' && (jsx(Icon, { icon: ZoomInIcon, color: "fixed-light", size: 24 }))] })] }) }));
99
107
  });
100
108
 
101
109
  export { UploadPictureCard as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mezzanine-ui/react",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "React components for mezzanine-ui",
5
5
  "author": "Mezzanine",
6
6
  "repository": {
@@ -31,9 +31,9 @@
31
31
  "@floating-ui/dom": "^1.7.4",
32
32
  "@floating-ui/react-dom": "^2.1.6",
33
33
  "@hello-pangea/dnd": "^18.0.1",
34
- "@mezzanine-ui/core": "1.0.0-rc.0",
35
- "@mezzanine-ui/icons": "1.0.0-rc.0",
36
- "@mezzanine-ui/system": "1.0.0-rc.0",
34
+ "@mezzanine-ui/core": "1.0.0-rc.1",
35
+ "@mezzanine-ui/icons": "1.0.0-rc.1",
36
+ "@mezzanine-ui/system": "1.0.0-rc.1",
37
37
  "@tanstack/react-virtual": "^3.13.13",
38
38
  "@types/react-transition-group": "^4.4.12",
39
39
  "clsx": "^2.1.1",