@mezzanine-ui/react 1.0.0-beta.5 → 1.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Accordion/Accordion.d.ts +23 -1
- package/Accordion/Accordion.js +59 -11
- package/Accordion/AccordionActions.d.ts +13 -0
- package/Accordion/AccordionActions.js +24 -0
- package/Accordion/AccordionContent.d.ts +9 -0
- package/Accordion/{AccordionDetails.js → AccordionContent.js} +4 -6
- package/Accordion/AccordionControlContext.d.ts +2 -2
- package/Accordion/AccordionGroup.d.ts +10 -0
- package/Accordion/AccordionGroup.js +26 -0
- package/Accordion/AccordionTitle.d.ts +14 -0
- package/Accordion/AccordionTitle.js +56 -0
- package/Accordion/index.d.ts +8 -4
- package/Accordion/index.js +4 -2
- package/AutoComplete/AutoComplete.d.ts +25 -6
- package/AutoComplete/AutoComplete.js +119 -30
- package/Backdrop/Backdrop.js +15 -19
- package/Breadcrumb/BreadcrumbDropdown.js +1 -1
- package/Breadcrumb/BreadcrumbItem.js +1 -1
- package/Breadcrumb/BreadcrumbOverflowMenuItem.js +1 -1
- package/Calendar/CalendarDays.js +1 -1
- package/Card/BaseCard.d.ts +11 -0
- package/Card/BaseCard.js +48 -0
- package/Card/BaseCardSkeleton.d.ts +14 -0
- package/Card/BaseCardSkeleton.js +18 -0
- package/Card/CardGroup.d.ts +47 -0
- package/Card/CardGroup.js +147 -0
- package/Card/FourThumbnailCard.d.ts +14 -0
- package/Card/FourThumbnailCard.js +73 -0
- package/Card/FourThumbnailCardSkeleton.d.ts +14 -0
- package/Card/FourThumbnailCardSkeleton.js +20 -0
- package/Card/QuickActionCard.d.ts +12 -0
- package/Card/QuickActionCard.js +23 -0
- package/Card/QuickActionCardSkeleton.d.ts +14 -0
- package/Card/QuickActionCardSkeleton.js +18 -0
- package/Card/SingleThumbnailCard.d.ts +13 -0
- package/Card/SingleThumbnailCard.js +44 -0
- package/Card/SingleThumbnailCardSkeleton.d.ts +19 -0
- package/Card/SingleThumbnailCardSkeleton.js +18 -0
- package/Card/Thumbnail.d.ts +12 -0
- package/Card/Thumbnail.js +18 -0
- package/Card/ThumbnailCardInfo.d.ts +34 -0
- package/Card/ThumbnailCardInfo.js +43 -0
- package/Card/index.d.ts +43 -4
- package/Card/index.js +19 -2
- package/Card/typings.d.ts +442 -0
- package/Checkbox/Checkbox.d.ts +8 -0
- package/Checkbox/Checkbox.js +3 -2
- package/Checkbox/CheckboxGroup.js +1 -1
- package/ContentHeader/ContentHeader.d.ts +22 -70
- package/ContentHeader/ContentHeader.js +1 -1
- package/ContentHeader/ContentHeaderResponsive.d.ts +9 -0
- package/ContentHeader/ContentHeaderResponsive.js +7 -0
- package/ContentHeader/utils.d.ts +3 -3
- package/ContentHeader/utils.js +66 -20
- package/Cropper/Cropper.d.ts +66 -0
- package/Cropper/Cropper.js +115 -0
- package/Cropper/CropperElement.d.ts +10 -0
- package/Cropper/CropperElement.js +892 -0
- package/Cropper/index.d.ts +18 -0
- package/Cropper/index.js +8 -0
- package/Cropper/tools.d.ts +90 -0
- package/Cropper/tools.js +143 -0
- package/Cropper/typings.d.ts +69 -0
- package/Cropper/utils/cropper-calculations.d.ts +39 -0
- package/Cropper/utils/cropper-calculations.js +95 -0
- package/DateTimePicker/DateTimePicker.d.ts +1 -1
- package/DateTimePicker/DateTimePicker.js +22 -5
- package/DateTimeRangePicker/DateTimeRangePicker.d.ts +34 -0
- package/DateTimeRangePicker/DateTimeRangePicker.js +118 -0
- package/DateTimeRangePicker/index.d.ts +2 -0
- package/DateTimeRangePicker/index.js +1 -0
- package/Drawer/Drawer.d.ts +132 -1
- package/Drawer/Drawer.js +47 -3
- package/Dropdown/Dropdown.d.ts +10 -4
- package/Dropdown/Dropdown.js +37 -42
- package/Dropdown/DropdownItem.d.ts +7 -1
- package/Dropdown/DropdownItem.js +36 -6
- package/Dropdown/DropdownItemCard.js +2 -1
- package/FloatingButton/FloatingButton.d.ts +21 -0
- package/FloatingButton/FloatingButton.js +18 -0
- package/FloatingButton/index.d.ts +2 -0
- package/FloatingButton/index.js +1 -0
- package/Form/FormField.d.ts +30 -7
- package/Form/FormField.js +12 -4
- package/Input/Input.js +12 -21
- package/Input/SelectButton/SelectButton.d.ts +25 -4
- package/Input/SelectButton/SelectButton.js +21 -9
- package/Message/Message.js +1 -1
- package/Modal/MediaPreviewModal.d.ts +11 -0
- package/Modal/MediaPreviewModal.js +24 -7
- package/Modal/Modal.d.ts +1 -1
- package/Modal/Modal.js +1 -1
- package/Modal/useModalContainer.js +6 -2
- package/MultipleDatePicker/MultipleDatePicker.d.ts +62 -0
- package/MultipleDatePicker/MultipleDatePicker.js +176 -0
- package/MultipleDatePicker/MultipleDatePickerTrigger.d.ts +56 -0
- package/MultipleDatePicker/MultipleDatePickerTrigger.js +92 -0
- package/MultipleDatePicker/index.d.ts +6 -0
- package/MultipleDatePicker/index.js +3 -0
- package/MultipleDatePicker/useMultipleDatePickerValue.d.ts +55 -0
- package/MultipleDatePicker/useMultipleDatePickerValue.js +68 -0
- package/Navigation/NavigationHeader.js +1 -1
- package/NotificationCenter/NotificationCenterDrawer.d.ts +10 -52
- package/NotificationCenter/NotificationCenterDrawer.js +128 -0
- package/NotificationCenter/index.d.ts +2 -0
- package/NotificationCenter/index.js +1 -0
- package/OverflowTooltip/index.d.ts +2 -2
- package/Picker/FormattedInput.d.ts +1 -1
- package/Picker/FormattedInput.js +2 -1
- package/Picker/PickerTriggerWithSeparator.d.ts +10 -0
- package/Picker/PickerTriggerWithSeparator.js +2 -2
- package/Picker/RangePickerTrigger.js +1 -1
- package/Picker/useDateInputFormatter.d.ts +6 -0
- package/Picker/useDateInputFormatter.js +4 -1
- package/Section/Section.d.ts +32 -0
- package/Section/Section.js +62 -0
- package/Section/index.d.ts +2 -0
- package/Select/Select.d.ts +11 -12
- package/Select/Select.js +13 -34
- package/Select/SelectTrigger.js +21 -7
- package/Select/index.d.ts +0 -4
- package/Select/index.js +0 -2
- package/Select/typings.d.ts +0 -4
- package/Select/useSelectTriggerTags.d.ts +1 -1
- package/Select/useSelectTriggerTags.js +9 -6
- package/Separator/Separator.d.ts +14 -0
- package/Separator/Separator.js +17 -0
- package/Separator/index.d.ts +2 -0
- package/Separator/index.js +1 -0
- package/Table/utils/useTableRowSelection.js +6 -0
- package/Tag/TagGroup.d.ts +4 -2
- package/Tag/TagGroup.js +7 -4
- package/TextField/TextField.d.ts +1 -1
- package/TextField/TextField.js +63 -9
- package/TimePanel/TimePanelColumn.js +30 -21
- package/TimeRangePicker/TimeRangePicker.d.ts +29 -0
- package/TimeRangePicker/TimeRangePicker.js +96 -0
- package/TimeRangePicker/index.d.ts +3 -0
- package/TimeRangePicker/index.js +2 -0
- package/TimeRangePicker/useTimeRangePickerValue.d.ts +30 -0
- package/TimeRangePicker/useTimeRangePickerValue.js +92 -0
- package/Transition/Rotate.js +2 -5
- package/index.d.ts +30 -28
- package/index.js +26 -27
- package/package.json +4 -4
- package/Accordion/AccordionDetails.d.ts +0 -9
- package/Accordion/AccordionSummary.d.ts +0 -18
- package/Accordion/AccordionSummary.js +0 -51
- package/Alert/Alert.d.ts +0 -20
- package/Alert/Alert.js +0 -18
- package/Alert/index.d.ts +0 -3
- package/Alert/index.js +0 -1
- package/AppBar/AppBar.d.ts +0 -14
- package/AppBar/AppBar.js +0 -33
- package/AppBar/AppBarBrand.d.ts +0 -4
- package/AppBar/AppBarBrand.js +0 -11
- package/AppBar/AppBarMain.d.ts +0 -4
- package/AppBar/AppBarMain.js +0 -11
- package/AppBar/AppBarSupport.d.ts +0 -4
- package/AppBar/AppBarSupport.js +0 -11
- package/AppBar/index.d.ts +0 -8
- package/AppBar/index.js +0 -4
- package/Card/Card.d.ts +0 -51
- package/Card/Card.js +0 -20
- package/Card/CardActions.d.ts +0 -34
- package/Card/CardActions.js +0 -15
- package/ConfirmActions/ConfirmActions.d.ts +0 -46
- package/ConfirmActions/ConfirmActions.js +0 -15
- package/ConfirmActions/index.d.ts +0 -2
- package/ConfirmActions/index.js +0 -1
- package/Popconfirm/Popconfirm.d.ts +0 -16
- package/Popconfirm/Popconfirm.js +0 -15
- package/Popconfirm/index.d.ts +0 -2
- package/Popconfirm/index.js +0 -1
- package/Popover/Popover.d.ts +0 -23
- package/Popover/Popover.js +0 -35
- package/Popover/index.d.ts +0 -2
- package/Popover/index.js +0 -1
- package/Select/Option.d.ts +0 -18
- package/Select/Option.js +0 -45
- package/Select/TreeSelect.d.ts +0 -67
- package/Select/TreeSelect.js +0 -198
- package/Tree/Tree.d.ts +0 -70
- package/Tree/Tree.js +0 -139
- package/Tree/TreeNode.d.ts +0 -40
- package/Tree/TreeNode.js +0 -50
- package/Tree/TreeNodeList.d.ts +0 -24
- package/Tree/TreeNodeList.js +0 -28
- package/Tree/getTreeNodeEntities.d.ts +0 -11
- package/Tree/getTreeNodeEntities.js +0 -92
- package/Tree/index.d.ts +0 -13
- package/Tree/index.js +0 -7
- package/Tree/toggleValue.d.ts +0 -4
- package/Tree/toggleValue.js +0 -19
- package/Tree/traverseTree.d.ts +0 -2
- package/Tree/traverseTree.js +0 -11
- package/Tree/typings.d.ts +0 -16
- package/Tree/useTreeExpandedValue.d.ts +0 -14
- package/Tree/useTreeExpandedValue.js +0 -33
package/Dropdown/DropdownItem.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import keycode from 'keycode';
|
|
4
4
|
import { useRef, useState, useCallback, useMemo, useEffect } from 'react';
|
|
5
5
|
import { dropdownClasses } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
@@ -69,7 +69,7 @@ function truncateArrayDepth(input, maxDepth = 3, warn = true) {
|
|
|
69
69
|
return truncate(input);
|
|
70
70
|
}
|
|
71
71
|
function DropdownItem(props) {
|
|
72
|
-
const { activeIndex, disabled = false, listboxId, listboxLabel, mode = 'single', options, value, type, maxHeight, actionConfig, onHover, onSelect, followText, headerContent, status, loadingText, emptyText, emptyIcon, onReachBottom, onLeaveBottom, onScroll, scrollbarDefer = true, scrollbarDisabled = false, scrollbarMaxWidth, scrollbarOptions, } = props;
|
|
72
|
+
const { activeIndex, disabled = false, listboxId, listboxLabel, mode = 'single', options, value, type, maxHeight, actionConfig, onHover, onSelect, followText, headerContent, status, loadingText, emptyText, emptyIcon, loadingPosition = 'full', onReachBottom, onLeaveBottom, onScroll, scrollbarDefer = true, scrollbarDisabled = false, scrollbarMaxWidth, scrollbarOptions, } = props;
|
|
73
73
|
const optionsContent = truncateArrayDepth(options, 3);
|
|
74
74
|
const listRef = useRef(null);
|
|
75
75
|
const listWrapperRef = useRef(null);
|
|
@@ -327,8 +327,10 @@ function DropdownItem(props) {
|
|
|
327
327
|
return renderDefaultOptions(optionList, startIndex);
|
|
328
328
|
};
|
|
329
329
|
const { elements: renderedOptions } = renderOptions(optionsContent, 0, -1);
|
|
330
|
-
// Show status when options are empty and status is provided
|
|
331
|
-
const
|
|
330
|
+
// Show full status when options are empty and status is provided, but not when loadingPosition is 'bottom'
|
|
331
|
+
const shouldShowFullStatus = optionsContent.length === 0 && status && loadingPosition !== 'bottom';
|
|
332
|
+
// Show bottom loading when status is loading and loadingPosition is bottom
|
|
333
|
+
const shouldShowBottomLoading = status === 'loading' && loadingPosition === 'bottom';
|
|
332
334
|
const listStyle = useMemo(() => {
|
|
333
335
|
if (!maxHeight) {
|
|
334
336
|
return undefined;
|
|
@@ -385,6 +387,34 @@ function DropdownItem(props) {
|
|
|
385
387
|
listWrapperRef.current = viewport;
|
|
386
388
|
wasAtBottomRef.current = getIsAtBottom(viewport);
|
|
387
389
|
}, [getIsAtBottom]);
|
|
390
|
+
// Track previous loading state to only scroll when loading appears (not when it disappears)
|
|
391
|
+
const prevShouldShowBottomLoadingRef = useRef(false);
|
|
392
|
+
// Auto-scroll to bottom when bottom loading appears and user was at bottom
|
|
393
|
+
useEffect(() => {
|
|
394
|
+
// Only scroll when loading appears (transitions from false to true)
|
|
395
|
+
const loadingJustAppeared = shouldShowBottomLoading && !prevShouldShowBottomLoadingRef.current;
|
|
396
|
+
prevShouldShowBottomLoadingRef.current = shouldShowBottomLoading;
|
|
397
|
+
if (!loadingJustAppeared)
|
|
398
|
+
return;
|
|
399
|
+
const scrollToBottom = (element) => {
|
|
400
|
+
// Use requestAnimationFrame to ensure DOM is updated after loading element is rendered
|
|
401
|
+
requestAnimationFrame(() => {
|
|
402
|
+
element.scrollTop = element.scrollHeight;
|
|
403
|
+
});
|
|
404
|
+
};
|
|
405
|
+
if (shouldUseScrollbar) {
|
|
406
|
+
const viewport = viewportRef.current;
|
|
407
|
+
if (viewport && wasAtBottomRef.current) {
|
|
408
|
+
scrollToBottom(viewport);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
const listWrapperElement = listWrapperRef.current;
|
|
413
|
+
if (listWrapperElement && maxHeight && wasAtBottomRef.current) {
|
|
414
|
+
scrollToBottom(listWrapperElement);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}, [shouldShowBottomLoading, shouldUseScrollbar, maxHeight]);
|
|
388
418
|
useEffect(() => {
|
|
389
419
|
if (shouldUseScrollbar) {
|
|
390
420
|
return;
|
|
@@ -455,8 +485,8 @@ function DropdownItem(props) {
|
|
|
455
485
|
};
|
|
456
486
|
}, [getIsAtBottom, shouldUseScrollbar, onReachBottom, onLeaveBottom, onScroll]);
|
|
457
487
|
return (jsxs("ul", { "aria-label": listboxLabel || (optionsContent.length === 0 ? 'Dropdown options' : undefined), className: dropdownClasses.list, id: listboxId, ref: listRef, role: "listbox", style: listStyle, tabIndex: -1, children: [hasHeader && (jsx("li", { className: dropdownClasses.listHeader, role: "presentation", ref: headerRef, children: jsx("div", { className: dropdownClasses.listHeaderInner, children: headerContent }) })), maxHeight
|
|
458
|
-
? (shouldUseScrollbar ? (jsx(Scrollbar, { className: dropdownClasses.listWrapper, defer: scrollbarDefer, disabled: false, events: scrollbarEvents, maxHeight: listWrapperStyle === null || listWrapperStyle === void 0 ? void 0 : listWrapperStyle.maxHeight, maxWidth: scrollbarMaxWidth, onViewportReady: handleViewportReady, options: scrollbarOptions, children:
|
|
459
|
-
:
|
|
488
|
+
? (shouldUseScrollbar ? (jsx(Scrollbar, { className: dropdownClasses.listWrapper, defer: scrollbarDefer, disabled: false, events: scrollbarEvents, maxHeight: listWrapperStyle === null || listWrapperStyle === void 0 ? void 0 : listWrapperStyle.maxHeight, maxWidth: scrollbarMaxWidth, onViewportReady: handleViewportReady, options: scrollbarOptions, children: shouldShowFullStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (jsxs(Fragment, { children: [renderedOptions, shouldShowBottomLoading && (jsx("li", { className: dropdownClasses.loadingMore, "aria-live": "polite", role: "status", children: jsx(DropdownStatus, { status: "loading", loadingText: loadingText }) }))] })) })) : (jsx("div", { ref: listWrapperRef, className: dropdownClasses.listWrapper, style: listWrapperStyle, children: shouldShowFullStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (jsxs(Fragment, { children: [renderedOptions, shouldShowBottomLoading && (jsx("li", { className: dropdownClasses.loadingMore, "aria-live": "polite", role: "status", children: jsx(DropdownStatus, { status: "loading", loadingText: loadingText }) }))] })) })))
|
|
489
|
+
: shouldShowFullStatus ? (jsx(DropdownStatus, { status: status, loadingText: loadingText, emptyText: emptyText, emptyIcon: emptyIcon })) : (jsxs(Fragment, { children: [renderedOptions, shouldShowBottomLoading && (jsx("li", { className: dropdownClasses.loadingMore, "aria-live": "polite", role: "status", children: jsx(DropdownStatus, { status: "loading", loadingText: loadingText }) }))] })), hasActions && (jsx("div", { ref: actionRef, children: jsx(DropdownAction, { ...actionConfig }) }))] }));
|
|
460
490
|
}
|
|
461
491
|
|
|
462
492
|
export { DropdownItem as default };
|
|
@@ -8,6 +8,7 @@ import Typography from '../Typography/Typography.js';
|
|
|
8
8
|
import { highlightText } from './highlightText.js';
|
|
9
9
|
import Icon from '../Icon/Icon.js';
|
|
10
10
|
import Checkbox from '../Checkbox/Checkbox.js';
|
|
11
|
+
import Separator from '../Separator/Separator.js';
|
|
11
12
|
|
|
12
13
|
function DropdownItemCard(props) {
|
|
13
14
|
const { active = false, appendIcon, appendContent, followText, id, label, level: levelProp, mode, name: _name, prependIcon, subTitle, validate, disabled, checked, defaultChecked, indeterminate = false, checkSite, onCheckedChange, onClick, className, onMouseEnter, showUnderline, } = props;
|
|
@@ -113,7 +114,7 @@ function DropdownItemCard(props) {
|
|
|
113
114
|
[dropdownClasses.cardDanger]: validate === 'danger',
|
|
114
115
|
}, className), id: id, role: "option", tabIndex: -1, onMouseEnter: onMouseEnter, onClick: handleClick, onKeyDown: handleKeyDown, children: jsxs("div", { className: dropdownClasses.cardContainer, children: [showPrependContent && (jsxs("div", { className: dropdownClasses.cardPrependContent, children: [prependIcon && jsx(Icon, { icon: prependIcon, color: iconColor }), checkSite === 'prefix' && mode === 'multiple' && (jsx(Checkbox, { checked: isChecked, disabled: disabled, indeterminate: indeterminate, onChange: handleCheckboxChange }))] })), jsxs("div", { className: dropdownClasses.cardBody, children: [cardLabel &&
|
|
115
116
|
renderHighlightedText(labelParts, dropdownClasses.cardTitle, labelId), subTitleParts.length > 0 &&
|
|
116
|
-
renderHighlightedText(subTitleParts, dropdownClasses.cardDescription)] }), showAppendContent && (jsxs("div", { className: dropdownClasses.cardAppendContent, children: [appendContent && (jsx(Typography, { color: "text-neutral-light", children: appendContent })), appendIcon && jsx(Icon, { icon: appendIcon, color: iconColor }), checkSite === 'suffix' && isChecked && (jsx(Icon, { icon: CheckedIcon, color: appendIconColor, size: 16 }))] }))] }) }), showUnderline && jsx("
|
|
117
|
+
renderHighlightedText(subTitleParts, dropdownClasses.cardDescription)] }), showAppendContent && (jsxs("div", { className: dropdownClasses.cardAppendContent, children: [appendContent && (jsx(Typography, { color: "text-neutral-light", children: appendContent })), appendIcon && jsx(Icon, { icon: appendIcon, color: iconColor }), checkSite === 'suffix' && isChecked && (jsx(Icon, { icon: CheckedIcon, color: appendIconColor, size: 16 }))] }))] }) }), showUnderline && (jsx("li", { role: "presentation", "aria-hidden": "true", children: jsx(Separator, { orientation: "horizontal", className: dropdownClasses.cardUnderline }) }))] }));
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
export { DropdownItemCard as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ButtonProps } from '../Button';
|
|
2
|
+
export interface FloatingButtonProps extends Omit<ButtonProps, 'variant' | 'size' | 'className' | 'tooltipPosition'> {
|
|
3
|
+
/**
|
|
4
|
+
* Auto hide floating button when `open` is true.
|
|
5
|
+
* @default false
|
|
6
|
+
*/
|
|
7
|
+
autoHideWhenOpen?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* The class name of the root element.
|
|
10
|
+
*/
|
|
11
|
+
className?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the floating button is in open state.
|
|
14
|
+
*/
|
|
15
|
+
open?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The react component for `mezzanine` floating button.
|
|
19
|
+
*/
|
|
20
|
+
declare const FloatingButton: import("react").ForwardRefExoticComponent<FloatingButtonProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
21
|
+
export default FloatingButton;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import Button from '../Button/Button.js';
|
|
5
|
+
import { floatingButtonClasses } from '@mezzanine-ui/core/floating-button';
|
|
6
|
+
import cx from 'clsx';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The react component for `mezzanine` floating button.
|
|
10
|
+
*/
|
|
11
|
+
const FloatingButton = forwardRef(function FloatingButton(props, ref) {
|
|
12
|
+
const { autoHideWhenOpen = false, children, className, open = false, ...rest } = props;
|
|
13
|
+
return (jsx("div", { ref: ref, className: cx(floatingButtonClasses.host, className), children: jsx(Button, { ...rest, className: cx(floatingButtonClasses.button, {
|
|
14
|
+
[floatingButtonClasses.buttonHidden]: autoHideWhenOpen && open,
|
|
15
|
+
}), variant: "base-primary", size: "main", tooltipPosition: "left", children: children }) }));
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export { FloatingButton as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './FloatingButton.js';
|
package/Form/FormField.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormFieldCounterColor,
|
|
1
|
+
import { ControlFieldSlotLayout, FormFieldCounterColor, FormFieldDensity, FormFieldLabelSpacing, FormFieldLayout } from '@mezzanine-ui/core/form';
|
|
2
2
|
import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
|
|
3
3
|
import { IconDefinition } from '@mezzanine-ui/icons';
|
|
4
4
|
import { SeverityWithInfo } from '@mezzanine-ui/system/severity';
|
|
@@ -13,6 +13,12 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
|
|
|
13
13
|
* @default FormFieldCounterColor.INFO
|
|
14
14
|
*/
|
|
15
15
|
counterColor?: FormFieldCounterColor;
|
|
16
|
+
/**
|
|
17
|
+
* The layout variant for the control field slot.
|
|
18
|
+
* Controls the visual styling and appearance of the input control area.
|
|
19
|
+
* @default ControlFieldSlotLayout.MAIN
|
|
20
|
+
*/
|
|
21
|
+
controlFieldSlotLayout?: ControlFieldSlotLayout;
|
|
16
22
|
/**
|
|
17
23
|
* To control the field passed from children whether should be disabled.
|
|
18
24
|
* The form message won't appear if disabled.
|
|
@@ -34,7 +40,7 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
|
|
|
34
40
|
/**
|
|
35
41
|
* The label text for the form field.
|
|
36
42
|
*/
|
|
37
|
-
label
|
|
43
|
+
label?: string;
|
|
38
44
|
/**
|
|
39
45
|
* The icon to display next to the label.
|
|
40
46
|
* When provided, displays an icon that shows a tooltip on hover.
|
|
@@ -50,6 +56,28 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
|
|
|
50
56
|
* Typically used to show "(optional)" or similar text.
|
|
51
57
|
*/
|
|
52
58
|
labelOptionalMarker?: string;
|
|
59
|
+
/**
|
|
60
|
+
* The spacing variant for the label area.
|
|
61
|
+
* Controls the padding and min-height of the label.
|
|
62
|
+
* Only applicable when layout is 'horizontal' or 'stretch'.
|
|
63
|
+
* Ignored when layout is 'vertical'.
|
|
64
|
+
* @default FormFieldLabelSpacing.MAIN
|
|
65
|
+
*/
|
|
66
|
+
labelSpacing?: FormFieldLabelSpacing;
|
|
67
|
+
/**
|
|
68
|
+
* The layout variant of the form field.
|
|
69
|
+
* Controls the arrangement direction of label and input.
|
|
70
|
+
* When set to 'vertical', density and labelSpacing are ignored.
|
|
71
|
+
* @default FormFieldLayout.HORIZONTAL
|
|
72
|
+
*/
|
|
73
|
+
layout?: FormFieldLayout;
|
|
74
|
+
/**
|
|
75
|
+
* The density variant of the form field.
|
|
76
|
+
* Controls the width of label and max-width of data entry.
|
|
77
|
+
* Only applicable when layout is 'horizontal' or 'stretch'.
|
|
78
|
+
* Ignored when layout is 'vertical'.
|
|
79
|
+
*/
|
|
80
|
+
density?: FormFieldDensity;
|
|
53
81
|
/**
|
|
54
82
|
* The name attribute for the form field.
|
|
55
83
|
* Used to identify the field in form submissions and as htmlFor in the label.
|
|
@@ -59,11 +87,6 @@ export interface FormFieldProps extends NativeElementPropsWithoutKeyAndRef<'div'
|
|
|
59
87
|
* To control the field passed from children whether should be required.
|
|
60
88
|
*/
|
|
61
89
|
required?: boolean;
|
|
62
|
-
/**
|
|
63
|
-
* The size variant of the form field.
|
|
64
|
-
* Controls the layout and spacing of label, input, and other elements.
|
|
65
|
-
*/
|
|
66
|
-
size: FormFieldSize;
|
|
67
90
|
/**
|
|
68
91
|
* The severity level of the form field.
|
|
69
92
|
* Used to indicate the importance or urgency of the field.
|
package/Form/FormField.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { forwardRef } from 'react';
|
|
3
|
-
import { formFieldClasses, FormFieldCounterColor } from '@mezzanine-ui/core/form';
|
|
3
|
+
import { ControlFieldSlotLayout, FormFieldLabelSpacing, FormFieldLayout, formFieldClasses, FormFieldCounterColor } from '@mezzanine-ui/core/form';
|
|
4
4
|
import { FormControlContext } from './FormControlContext.js';
|
|
5
5
|
import FormHintText from './FormHintText.js';
|
|
6
6
|
import FormLabel from './FormLabel.js';
|
|
@@ -10,17 +10,25 @@ import cx from 'clsx';
|
|
|
10
10
|
* The React component for `mezzanine` form field.
|
|
11
11
|
*/
|
|
12
12
|
const FormField = forwardRef(function FormField(props, ref) {
|
|
13
|
-
const { children, className, counter, counterColor, disabled = false, fullWidth = false, hintText, hintTextIcon, label, labelInformationIcon, labelInformationText, labelOptionalMarker, name, required = false,
|
|
13
|
+
const { children, className, counter, counterColor, controlFieldSlotLayout = ControlFieldSlotLayout.MAIN, density, disabled = false, fullWidth = false, hintText, hintTextIcon, label, labelInformationIcon, labelInformationText, labelOptionalMarker, labelSpacing = FormFieldLabelSpacing.MAIN, layout = FormFieldLayout.HORIZONTAL, name, required = false, severity = 'info', ...rest } = props;
|
|
14
14
|
const formControl = {
|
|
15
15
|
disabled,
|
|
16
16
|
fullWidth,
|
|
17
17
|
required,
|
|
18
18
|
severity,
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
const shouldApplyDensity = density && layout !== FormFieldLayout.VERTICAL;
|
|
21
|
+
const densityClass = shouldApplyDensity
|
|
22
|
+
? formFieldClasses.density(density)
|
|
23
|
+
: undefined;
|
|
24
|
+
const shouldApplyLabelSpacing = layout !== FormFieldLayout.VERTICAL;
|
|
25
|
+
const labelSpacingClass = shouldApplyLabelSpacing
|
|
26
|
+
? formFieldClasses.labelSpacing(labelSpacing)
|
|
27
|
+
: undefined;
|
|
28
|
+
return (jsx("div", { ...rest, ref: ref, className: cx(formFieldClasses.host, formFieldClasses.layout(layout), densityClass, {
|
|
21
29
|
[formFieldClasses.disabled]: disabled,
|
|
22
30
|
[formFieldClasses.fullWidth]: fullWidth,
|
|
23
|
-
}, className), children: jsxs(FormControlContext.Provider, { value: formControl, children: [jsx(FormLabel, { className: formFieldClasses.labelArea, htmlFor: name, informationIcon: labelInformationIcon, informationText: labelInformationText, labelText: label, optionalMarker: labelOptionalMarker }), jsxs("div", { className: cx(formFieldClasses.dataEntry), children: [children, hintText || hintTextIcon || counter ? (jsxs("div", { className: cx(formFieldClasses.hintTextAndCounterArea, {
|
|
31
|
+
}, className), children: jsxs(FormControlContext.Provider, { value: formControl, children: [label && (jsx(FormLabel, { className: cx(formFieldClasses.labelArea, labelSpacingClass), htmlFor: name, informationIcon: labelInformationIcon, informationText: labelInformationText, labelText: label, optionalMarker: labelOptionalMarker })), jsxs("div", { className: cx(formFieldClasses.dataEntry), children: [jsx("div", { className: cx(`${formFieldClasses.controlFieldSlot}--${controlFieldSlotLayout}`), children: children }), hintText || hintTextIcon || counter ? (jsxs("div", { className: cx(formFieldClasses.hintTextAndCounterArea, {
|
|
24
32
|
[formFieldClasses.hintTextAndCounterArea + '--align-right']: !(hintText || hintTextIcon) && counter,
|
|
25
33
|
}), children: [(hintText || hintTextIcon) && (jsx(FormHintText, { hintText: hintText, hintTextIcon: hintTextIcon, severity: severity })), counter && (jsx("span", { className: cx(formFieldClasses.counter, formFieldClasses.counterColor(counterColor || FormFieldCounterColor.INFO)), children: counter }))] })) : null] })] }) }));
|
|
26
34
|
});
|
package/Input/Input.js
CHANGED
|
@@ -8,7 +8,6 @@ import { useComposeRefs } from '../hooks/useComposeRefs.js';
|
|
|
8
8
|
import { formatNumberWithCommas } from '../utils/format-number-with-commas.js';
|
|
9
9
|
import { parseNumberWithCommas } from '../utils/parse-number-with-commas.js';
|
|
10
10
|
import Icon from '../Icon/Icon.js';
|
|
11
|
-
import Dropdown from '../Dropdown/Dropdown.js';
|
|
12
11
|
import SelectButton from './SelectButton/SelectButton.js';
|
|
13
12
|
import ActionButton from './ActionButton/ActionButton.js';
|
|
14
13
|
import SpinnerButton from './SpinnerButton/SpinnerButton.js';
|
|
@@ -125,6 +124,7 @@ const Input = forwardRef(function Input(props, ref) {
|
|
|
125
124
|
break;
|
|
126
125
|
}
|
|
127
126
|
case 'currency': {
|
|
127
|
+
// 需注意 input type 不應是 number,因為要允許輸入格式化後的字串(例如 1,000)
|
|
128
128
|
const currencyProps = props;
|
|
129
129
|
const { step = 1, max, min, onSpinUp, onSpinDown } = currencyProps;
|
|
130
130
|
// 預設置右對齊
|
|
@@ -167,41 +167,32 @@ const Input = forwardRef(function Input(props, ref) {
|
|
|
167
167
|
const { actionButton } = actionProps;
|
|
168
168
|
if (actionButton.position === 'prefix') {
|
|
169
169
|
const { ...restActionButtonProps } = actionButton;
|
|
170
|
-
|
|
170
|
+
const actionDisabled = typeof restActionButtonProps.disabled === 'boolean'
|
|
171
|
+
? restActionButtonProps.disabled
|
|
172
|
+
: disabled || readonly;
|
|
173
|
+
prefixExternalButton = (jsx(ActionButton, { ...restActionButtonProps, disabled: actionDisabled, size: size }));
|
|
171
174
|
}
|
|
172
175
|
if (actionButton.position === 'suffix') {
|
|
173
176
|
const { ...restActionButtonProps } = actionButton;
|
|
174
|
-
|
|
177
|
+
const actionDisabled = typeof restActionButtonProps.disabled === 'boolean'
|
|
178
|
+
? restActionButtonProps.disabled
|
|
179
|
+
: disabled || readonly;
|
|
180
|
+
suffixExternalButton = (jsx(ActionButton, { ...restActionButtonProps, disabled: actionDisabled, size: size }));
|
|
175
181
|
}
|
|
176
182
|
break;
|
|
177
183
|
}
|
|
178
184
|
case 'select': {
|
|
179
185
|
const selectProps = props;
|
|
180
|
-
const { selectButton, options, dropdownWidth = 120, dropdownMaxHeight = 114, } = selectProps;
|
|
181
|
-
const defaultOptions = options || [];
|
|
182
|
-
const selectedOptions = defaultOptions.length > 0
|
|
183
|
-
? defaultOptions.map((option) => ({
|
|
184
|
-
...option,
|
|
185
|
-
...(option.id === selectProps.selectedValue
|
|
186
|
-
? { checkSite: 'suffix' }
|
|
187
|
-
: {}),
|
|
188
|
-
}))
|
|
189
|
-
: [];
|
|
186
|
+
const { selectButton, options, dropdownWidth = 120, dropdownMaxHeight = 114, dropdownPlacement = 'bottom-start', } = selectProps;
|
|
190
187
|
if (selectButton.position === 'both' ||
|
|
191
188
|
selectButton.position === 'prefix') {
|
|
192
189
|
const { ...restSelectButtonProps } = selectButton;
|
|
193
|
-
prefixExternalButton = (jsx(
|
|
194
|
-
var _a;
|
|
195
|
-
(_a = selectProps.onSelect) === null || _a === void 0 ? void 0 : _a.call(selectProps, option.id);
|
|
196
|
-
}, children: jsx(SelectButton, { ...restSelectButtonProps, disabled: restSelectButtonProps.disabled || disabled, size: size }) }));
|
|
190
|
+
prefixExternalButton = (jsx(SelectButton, { ...restSelectButtonProps, disabled: restSelectButtonProps.disabled || disabled, dropdownMaxHeight: dropdownMaxHeight, dropdownPlacement: dropdownPlacement, dropdownWidth: dropdownWidth, onSelect: selectProps.onSelect, options: options, size: size }));
|
|
197
191
|
}
|
|
198
192
|
if (selectButton.position === 'both' ||
|
|
199
193
|
selectButton.position === 'suffix') {
|
|
200
194
|
const { ...restSelectButtonProps } = selectButton;
|
|
201
|
-
suffixExternalButton = (jsx(
|
|
202
|
-
var _a;
|
|
203
|
-
(_a = selectProps.onSelect) === null || _a === void 0 ? void 0 : _a.call(selectProps, option.id);
|
|
204
|
-
}, children: jsx(SelectButton, { ...restSelectButtonProps, disabled: restSelectButtonProps.disabled || disabled, size: size }) }));
|
|
195
|
+
suffixExternalButton = (jsx(SelectButton, { ...restSelectButtonProps, disabled: restSelectButtonProps.disabled || disabled, dropdownMaxHeight: dropdownMaxHeight, dropdownPlacement: dropdownPlacement, dropdownWidth: dropdownWidth, onSelect: selectProps.onSelect, options: options, size: size }));
|
|
205
196
|
}
|
|
206
197
|
break;
|
|
207
198
|
}
|
|
@@ -1,20 +1,41 @@
|
|
|
1
1
|
import { InputSize } from '@mezzanine-ui/core/input';
|
|
2
|
+
import { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
3
|
+
import { PopperPlacement } from '../../Popper';
|
|
2
4
|
import { NativeElementPropsWithoutKeyAndRef } from '../../utils/jsx-types';
|
|
3
|
-
export interface SelectButtonProps extends Omit<NativeElementPropsWithoutKeyAndRef<'button'>, 'type' | '
|
|
5
|
+
export interface SelectButtonProps extends Omit<NativeElementPropsWithoutKeyAndRef<'button'>, 'disabled' | 'onSelect' | 'type' | 'selectedValue'> {
|
|
4
6
|
/**
|
|
5
7
|
* Whether the select button is disabled.
|
|
6
8
|
*/
|
|
7
9
|
disabled?: boolean;
|
|
8
10
|
/**
|
|
9
|
-
* The
|
|
11
|
+
* The custom width of the dropdown.
|
|
10
12
|
*/
|
|
11
|
-
|
|
13
|
+
dropdownWidth?: number | string;
|
|
14
|
+
/**
|
|
15
|
+
* The max height of the dropdown.
|
|
16
|
+
*/
|
|
17
|
+
dropdownMaxHeight?: number | string;
|
|
18
|
+
/**
|
|
19
|
+
* The placement of the dropdown.
|
|
20
|
+
*/
|
|
21
|
+
dropdownPlacement?: PopperPlacement;
|
|
22
|
+
/**
|
|
23
|
+
* The options of the dropdown.
|
|
24
|
+
*/
|
|
25
|
+
options?: DropdownOption[];
|
|
26
|
+
/**
|
|
27
|
+
* Callback when an option is selected.
|
|
28
|
+
*/
|
|
29
|
+
onSelect?: (value: string) => void;
|
|
12
30
|
/**
|
|
13
31
|
* The size of select button.
|
|
14
32
|
* @default 'main'
|
|
15
33
|
*/
|
|
16
34
|
size?: InputSize;
|
|
35
|
+
/**
|
|
36
|
+
* The value of select button.
|
|
37
|
+
*/
|
|
38
|
+
value?: string;
|
|
17
39
|
}
|
|
18
|
-
/** @TODO dropdown menu with button */
|
|
19
40
|
declare const SelectButton: import("react").ForwardRefExoticComponent<SelectButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
20
41
|
export default SelectButton;
|
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
3
|
import { inputSelectButtonClasses } from '@mezzanine-ui/core/input';
|
|
4
|
-
import { forwardRef } from 'react';
|
|
4
|
+
import { forwardRef, useState, useCallback } from 'react';
|
|
5
5
|
import Rotate from '../../Transition/Rotate.js';
|
|
6
6
|
import { ChevronDownIcon } from '@mezzanine-ui/icons';
|
|
7
7
|
import { MOTION_EASING, MOTION_DURATION } from '@mezzanine-ui/system/motion';
|
|
8
|
+
import Dropdown from '../../Dropdown/Dropdown.js';
|
|
8
9
|
import Icon from '../../Icon/Icon.js';
|
|
9
10
|
import cx from 'clsx';
|
|
10
11
|
|
|
11
|
-
/** @TODO dropdown menu with button */
|
|
12
12
|
const SelectButton = forwardRef(function SelectButton(props, ref) {
|
|
13
|
-
const { className, disabled,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
const { className, disabled, dropdownMaxHeight = 114, dropdownPlacement = 'bottom-start', dropdownWidth = 120, onSelect, options = [], size = 'main', value, ...rest } = props;
|
|
14
|
+
const [open, setOpen] = useState(false);
|
|
15
|
+
const handleOpen = useCallback(() => {
|
|
16
|
+
if (!disabled) {
|
|
17
|
+
setOpen(true);
|
|
18
|
+
}
|
|
19
|
+
}, [disabled]);
|
|
20
|
+
const handleClose = useCallback(() => {
|
|
21
|
+
setOpen(false);
|
|
22
|
+
}, []);
|
|
23
|
+
const handleSelect = useCallback((option) => {
|
|
24
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(option.id);
|
|
25
|
+
}, [onSelect]);
|
|
26
|
+
const dropdownOptions = options.map((option) => ({
|
|
27
|
+
...option,
|
|
28
|
+
...(option.id === value ? { checkSite: 'suffix' } : {}),
|
|
29
|
+
}));
|
|
30
|
+
return (jsx(Dropdown, { customWidth: dropdownWidth, disabled: disabled, maxHeight: dropdownMaxHeight, onClose: handleClose, onOpen: handleOpen, onSelect: handleSelect, options: dropdownOptions, placement: dropdownPlacement, value: value, children: jsxs("button", { ref: ref, type: "button", disabled: disabled, className: cx(inputSelectButtonClasses.host, disabled && inputSelectButtonClasses.disabled, size === 'main' ? inputSelectButtonClasses.main : inputSelectButtonClasses.sub, className), title: value, ...rest, children: [jsx("span", { className: inputSelectButtonClasses.text, children: value }), jsx(Rotate, { in: open, duration: MOTION_DURATION.fast, easing: MOTION_EASING.standard, children: jsx(Icon, { className: inputSelectButtonClasses.icon, icon: ChevronDownIcon, size: 16 }) })] }) }));
|
|
19
31
|
});
|
|
20
32
|
|
|
21
33
|
export { SelectButton as default };
|
package/Message/Message.js
CHANGED
|
@@ -5,8 +5,8 @@ import { messageClasses, messageIcons } from '@mezzanine-ui/core/message';
|
|
|
5
5
|
import { messageTimerController } from './MessageTimerController.js';
|
|
6
6
|
import Translate from '../Transition/Translate.js';
|
|
7
7
|
import Icon from '../Icon/Icon.js';
|
|
8
|
-
import { createNotifier } from '../Notifier/createNotifier.js';
|
|
9
8
|
import cx from 'clsx';
|
|
9
|
+
import { createNotifier } from '../Notifier/createNotifier.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* The react component for `mezzanine` message.
|
|
@@ -21,6 +21,17 @@ export interface MediaPreviewModalProps extends Omit<ModalContainerProps, 'child
|
|
|
21
21
|
* @default false
|
|
22
22
|
*/
|
|
23
23
|
disablePrev?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Enable circular navigation (wrap around at boundaries).
|
|
26
|
+
* When enabled, navigating past the last item goes to the first,
|
|
27
|
+
* and navigating before the first item goes to the last.
|
|
28
|
+
*
|
|
29
|
+
* Note: This only applies in uncontrolled mode. In controlled mode
|
|
30
|
+
* (when onNext/onPrev are provided), you must implement circular
|
|
31
|
+
* navigation logic in your callbacks.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
enableCircularNavigation?: boolean;
|
|
24
35
|
/**
|
|
25
36
|
* Array of media items to display.
|
|
26
37
|
* Each item should be a valid image URL or React node.
|
|
@@ -15,7 +15,7 @@ import cx from 'clsx';
|
|
|
15
15
|
* Displays media items with navigation controls and a close button.
|
|
16
16
|
*/
|
|
17
17
|
const MediaPreviewModal = forwardRef(function MediaPreviewModal(props, ref) {
|
|
18
|
-
const { className, container, currentIndex: controlledIndex, defaultIndex = 0, disableCloseOnBackdropClick = false, disableCloseOnEscapeKeyDown = false, disableNext = false, disablePortal = false, disablePrev = false, mediaItems, onBackdropClick, onClose, onIndexChange, onNext, onPrev, open, showPaginationIndicator = true, ...rest } = props;
|
|
18
|
+
const { className, container, currentIndex: controlledIndex, defaultIndex = 0, disableCloseOnBackdropClick = false, disableCloseOnEscapeKeyDown = false, disableNext = false, disablePortal = false, disablePrev = false, enableCircularNavigation = false, mediaItems, onBackdropClick, onClose, onIndexChange, onNext, onPrev, open, showPaginationIndicator = true, ...rest } = props;
|
|
19
19
|
const { Container: ModalContainer } = useModalContainer();
|
|
20
20
|
// Determine if component is in controlled mode
|
|
21
21
|
const isControlled = controlledIndex !== undefined;
|
|
@@ -37,7 +37,13 @@ const MediaPreviewModal = forwardRef(function MediaPreviewModal(props, ref) {
|
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
39
|
// Uncontrolled mode: update internal state
|
|
40
|
-
|
|
40
|
+
let nextIndex;
|
|
41
|
+
if (enableCircularNavigation) {
|
|
42
|
+
nextIndex = (currentIndex + 1) % mediaItems.length;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
nextIndex = Math.min(currentIndex + 1, mediaItems.length - 1);
|
|
46
|
+
}
|
|
41
47
|
setInternalIndex(nextIndex);
|
|
42
48
|
onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(nextIndex);
|
|
43
49
|
}
|
|
@@ -49,14 +55,25 @@ const MediaPreviewModal = forwardRef(function MediaPreviewModal(props, ref) {
|
|
|
49
55
|
}
|
|
50
56
|
else {
|
|
51
57
|
// Uncontrolled mode: update internal state
|
|
52
|
-
|
|
58
|
+
let prevIndex;
|
|
59
|
+
if (enableCircularNavigation) {
|
|
60
|
+
prevIndex =
|
|
61
|
+
(currentIndex - 1 + mediaItems.length) % mediaItems.length;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
prevIndex = Math.max(currentIndex - 1, 0);
|
|
65
|
+
}
|
|
53
66
|
setInternalIndex(prevIndex);
|
|
54
67
|
onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(prevIndex);
|
|
55
68
|
}
|
|
56
69
|
};
|
|
57
70
|
// Auto-calculate disable states for uncontrolled mode
|
|
58
|
-
const isNextDisabled =
|
|
59
|
-
|
|
71
|
+
const isNextDisabled = enableCircularNavigation
|
|
72
|
+
? false
|
|
73
|
+
: disableNext || currentIndex >= mediaItems.length - 1;
|
|
74
|
+
const isPrevDisabled = enableCircularNavigation
|
|
75
|
+
? false
|
|
76
|
+
: disablePrev || currentIndex <= 0;
|
|
60
77
|
const [displayedIndices, setDisplayedIndices] = useState([
|
|
61
78
|
currentIndex,
|
|
62
79
|
]);
|
|
@@ -148,8 +165,8 @@ const MediaPreviewModal = forwardRef(function MediaPreviewModal(props, ref) {
|
|
|
148
165
|
enter: MOTION_DURATION.fast,
|
|
149
166
|
exit: MOTION_DURATION.fast,
|
|
150
167
|
}, easing: {
|
|
151
|
-
enter: MOTION_EASING.
|
|
152
|
-
exit: MOTION_EASING.
|
|
168
|
+
enter: MOTION_EASING.standard,
|
|
169
|
+
exit: MOTION_EASING.standard,
|
|
153
170
|
}, in: isCurrent, children: mediaElement.element }, index));
|
|
154
171
|
};
|
|
155
172
|
return (jsxs(ModalContainer, { className: modalClasses.overlay, container: container, disableCloseOnBackdropClick: disableCloseOnBackdropClick, disableCloseOnEscapeKeyDown: disableCloseOnEscapeKeyDown, disablePortal: disablePortal, onBackdropClick: onBackdropClick, onClose: onClose, open: open, ref: ref, children: [jsx("div", { ...rest, className: cx(modalClasses.host, modalClasses.mediaPreview, className), role: "dialog", children: jsx("div", { className: modalClasses.mediaPreviewContent, children: jsx("div", { className: modalClasses.mediaPreviewMediaContainer, children: displayedIndices.map((index) => renderMedia(index)) }) }) }), jsx(ClearActions, { className: modalClasses.mediaPreviewCloseButton, onClick: onClose, type: "embedded", variant: "contrast" }), mediaItems.length > 1 && (jsx("button", { "aria-disabled": isPrevDisabled, "aria-label": "Previous media", className: cx(modalClasses.mediaPreviewNavButton, modalClasses.mediaPreviewNavButtonPrev), disabled: isPrevDisabled, onClick: handlePrev, title: "Previous", type: "button", children: jsx(Icon, { icon: ChevronLeftIcon, size: 16, color: "fixed-light" }) })), mediaItems.length > 1 && (jsx("button", { "aria-disabled": isNextDisabled, "aria-label": "Next media", className: cx(modalClasses.mediaPreviewNavButton, modalClasses.mediaPreviewNavButtonNext), disabled: isNextDisabled, onClick: handleNext, title: "Next", type: "button", children: jsx(Icon, { icon: ChevronRightIcon, size: 16, color: "fixed-light" }) })), showPaginationIndicator && mediaItems.length > 1 && (jsxs("div", { "aria-label": `Page ${currentIndex + 1} of ${mediaItems.length}`, className: modalClasses.mediaPreviewPaginationIndicator, children: [currentIndex + 1, "/", mediaItems.length] }))] }));
|
package/Modal/Modal.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ interface CommonModalProps extends Omit<ModalContainerProps, 'children'>, Pick<N
|
|
|
22
22
|
modalStatusType?: ModalStatusType;
|
|
23
23
|
/**
|
|
24
24
|
* Controls whether or not to show dismiss button at top-end.
|
|
25
|
-
* @default
|
|
25
|
+
* @default true
|
|
26
26
|
*/
|
|
27
27
|
showDismissButton?: boolean;
|
|
28
28
|
}
|
package/Modal/Modal.js
CHANGED
|
@@ -12,7 +12,7 @@ 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 =
|
|
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;
|
|
16
16
|
const modalControl = useMemo(() => ({
|
|
17
17
|
loading,
|
|
18
18
|
modalStatusType: modalStatusType,
|
|
@@ -3,8 +3,9 @@ import { modalClasses } from '@mezzanine-ui/core/modal';
|
|
|
3
3
|
import { forwardRef, useState } from 'react';
|
|
4
4
|
import { useDocumentEscapeKeyDown } from '../hooks/useDocumentEscapeKeyDown.js';
|
|
5
5
|
import useTopStack from '../_internal/SlideFadeOverlay/useTopStack.js';
|
|
6
|
+
import { MOTION_EASING } from '@mezzanine-ui/system/motion';
|
|
6
7
|
import Backdrop from '../Backdrop/Backdrop.js';
|
|
7
|
-
import
|
|
8
|
+
import Scale from '../Transition/Scale.js';
|
|
8
9
|
import cx from 'clsx';
|
|
9
10
|
|
|
10
11
|
const defaultOptions = {
|
|
@@ -35,7 +36,10 @@ const ModalContainer = forwardRef(function ModalContainer(props, ref) {
|
|
|
35
36
|
if (!open && exited) {
|
|
36
37
|
return null;
|
|
37
38
|
}
|
|
38
|
-
return (jsx(Backdrop, { className: cx(className), container: container, disableCloseOnBackdropClick: disableCloseOnBackdropClick, disablePortal: disablePortal, onBackdropClick: onBackdropClick, onClose: onClose, open: open, role: "presentation", children: jsx(
|
|
39
|
+
return (jsx(Backdrop, { className: cx(className), container: container, disableCloseOnBackdropClick: disableCloseOnBackdropClick, disablePortal: disablePortal, onBackdropClick: onBackdropClick, onClose: onClose, open: open, role: "presentation", children: jsx(Scale, { easing: {
|
|
40
|
+
enter: MOTION_EASING.entrance,
|
|
41
|
+
exit: MOTION_EASING.exit,
|
|
42
|
+
}, in: open, onEntered: () => setExited(false), onExited: () => setExited(true), children: jsx("div", { className: modalClasses.contentWrapper, ref: ref, children: children }) }) }));
|
|
39
43
|
});
|
|
40
44
|
function useModalContainer() {
|
|
41
45
|
return {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DateType } from '@mezzanine-ui/core/calendar';
|
|
2
|
+
import { MultipleDatePickerValue } from '@mezzanine-ui/core/multiple-date-picker';
|
|
3
|
+
import { CalendarProps } from '../Calendar';
|
|
4
|
+
import { CalendarFooterActionsProps } from '../Calendar/CalendarFooterActions';
|
|
5
|
+
import { InputTriggerPopperProps } from '../_internal/InputTriggerPopper';
|
|
6
|
+
import { MultipleDatePickerTriggerProps } from './MultipleDatePickerTrigger';
|
|
7
|
+
export interface MultipleDatePickerProps extends Pick<MultipleDatePickerTriggerProps, 'className' | 'clearable' | 'disabled' | 'error' | 'fullWidth' | 'overflowStrategy' | 'prefix' | 'readOnly' | 'size'>, Pick<CalendarProps, 'disabledMonthSwitch' | 'disableOnNext' | 'disableOnPrev' | 'disableOnDoubleNext' | 'disableOnDoublePrev' | 'disabledYearSwitch' | 'displayMonthLocale' | 'isDateDisabled'> {
|
|
8
|
+
/**
|
|
9
|
+
* Custom action button props. Allows overriding confirm/cancel button text and behavior.
|
|
10
|
+
*/
|
|
11
|
+
actions?: Partial<CalendarFooterActionsProps['actions']>;
|
|
12
|
+
/**
|
|
13
|
+
* Other calendar props you may provide to `Calendar`.
|
|
14
|
+
*/
|
|
15
|
+
calendarProps?: Omit<CalendarProps, 'disableOnNext' | 'disableOnPrev' | 'disableOnDoubleNext' | 'disableOnDoublePrev' | 'displayMonthLocale' | 'isDateDisabled' | 'locale' | 'mode' | 'onChange' | 'onMonthControlClick' | 'onNext' | 'onDoubleNext' | 'onPrev' | 'onDoublePrev' | 'onYearControlClick' | 'referenceDate' | 'updateReferenceDate' | 'value'>;
|
|
16
|
+
/**
|
|
17
|
+
* The format for displaying date in tags.
|
|
18
|
+
* @default 'YYYY-MM-DD'
|
|
19
|
+
*/
|
|
20
|
+
format?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Maximum number of dates that can be selected.
|
|
23
|
+
*/
|
|
24
|
+
maxSelections?: number;
|
|
25
|
+
/**
|
|
26
|
+
* A function that fires when calendar toggle.
|
|
27
|
+
*/
|
|
28
|
+
onCalendarToggle?: (open: boolean) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Change handler. Called when user confirms the selection.
|
|
31
|
+
*/
|
|
32
|
+
onChange?: (value: MultipleDatePickerValue) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Placeholder text when no dates are selected.
|
|
35
|
+
*/
|
|
36
|
+
placeholder?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Other props you may provide to `Popper` component.
|
|
39
|
+
*/
|
|
40
|
+
popperProps?: Omit<InputTriggerPopperProps, 'anchor' | 'children' | 'fadeProps' | 'open'>;
|
|
41
|
+
/**
|
|
42
|
+
* The reference date for getting calendars. Default to current time.
|
|
43
|
+
*/
|
|
44
|
+
referenceDate?: DateType;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the input is required.
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
required?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Controlled value - array of selected dates.
|
|
52
|
+
* @default []
|
|
53
|
+
*/
|
|
54
|
+
value?: MultipleDatePickerValue;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The react component for `mezzanine` multiple date picker.
|
|
58
|
+
* Allows selecting multiple dates from a calendar with manual confirmation.
|
|
59
|
+
* Notice that any component related to date-picker should be used along with `CalendarContext`.
|
|
60
|
+
*/
|
|
61
|
+
declare const MultipleDatePicker: import("react").ForwardRefExoticComponent<MultipleDatePickerProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
62
|
+
export default MultipleDatePicker;
|