@moderneinc/design-system-components 7.7.0-next.19b91c → 7.7.0-next.7feadd
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/dist/Button/Button.d.ts +7 -5
- package/dist/index.d.ts +4 -3
- package/dist/index.esm.js +96 -61
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +122 -87
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -11,9 +11,10 @@ var Alert = require('@mui/material/Alert');
|
|
|
11
11
|
var ButtonBase = require('@mui/material/ButtonBase');
|
|
12
12
|
var lucideReact = require('lucide-react');
|
|
13
13
|
var IconButton = require('@mui/material/IconButton');
|
|
14
|
-
var
|
|
14
|
+
var react = require('react');
|
|
15
15
|
var Breadcrumbs = require('@mui/material/Breadcrumbs');
|
|
16
16
|
var Link = require('@mui/material/Link');
|
|
17
|
+
var Button = require('@mui/material/Button');
|
|
17
18
|
var CircularProgress = require('@mui/material/CircularProgress');
|
|
18
19
|
var MuiToggleButton = require('@mui/material/ToggleButton');
|
|
19
20
|
var MuiToggleButtonGroup = require('@mui/material/ToggleButtonGroup');
|
|
@@ -21,7 +22,6 @@ var MuiCard = require('@mui/material/Card');
|
|
|
21
22
|
var Checkbox = require('@mui/material/Checkbox');
|
|
22
23
|
var xDataGrid = require('@mui/x-data-grid');
|
|
23
24
|
var xDataGridPro = require('@mui/x-data-grid-pro');
|
|
24
|
-
var Button = require('@mui/material/Button');
|
|
25
25
|
var Divider = require('@mui/material/Divider');
|
|
26
26
|
var InputAdornment = require('@mui/material/InputAdornment');
|
|
27
27
|
var InputBase = require('@mui/material/InputBase');
|
|
@@ -664,7 +664,7 @@ const StyledIconButton = styles.styled(IconButton, {
|
|
|
664
664
|
},
|
|
665
665
|
}));
|
|
666
666
|
const ModBanner = ({ intent = 'info', type = 'outlined', message, messagePosition = 'left', linkText, showClose = false, icon, onClose, onLinkClick, ...props }) => {
|
|
667
|
-
const [dismissed, setDismissed] =
|
|
667
|
+
const [dismissed, setDismissed] = react.useState(false);
|
|
668
668
|
const handleClose = () => {
|
|
669
669
|
setDismissed(true);
|
|
670
670
|
onClose?.();
|
|
@@ -742,39 +742,34 @@ function ModBreadcrumbs({ children, className }) {
|
|
|
742
742
|
return (jsxRuntime.jsx(StyledBreadcrumbs, { separator: jsxRuntime.jsx(lucideReact.ChevronRight, { size: 10.67, color: designSystemTokens.semanticColors.color.icon.utility }), className: className, "aria-label": "breadcrumb", children: children }));
|
|
743
743
|
}
|
|
744
744
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
'size',
|
|
749
|
-
'loading',
|
|
750
|
-
'startIcon',
|
|
751
|
-
'endIcon',
|
|
752
|
-
'fullWidth',
|
|
753
|
-
'disableElevation',
|
|
754
|
-
];
|
|
755
|
-
const StyledButtonBase$1 = styles.styled(ButtonBase, {
|
|
756
|
-
shouldForwardProp: prop => !buttonOnlyProps.includes(prop),
|
|
757
|
-
})(({ theme, variant = 'primary', size = 'medium', loading = false }) => {
|
|
745
|
+
const StyledButton = styles.styled(Button, {
|
|
746
|
+
shouldForwardProp: prop => prop !== 'buttonVariant' && prop !== 'buttonSize',
|
|
747
|
+
})(({ theme, buttonVariant: variant, buttonSize: size }) => {
|
|
758
748
|
// Size configurations
|
|
759
749
|
const sizeConfig = {
|
|
760
750
|
small: {
|
|
761
751
|
height: 32,
|
|
762
|
-
|
|
752
|
+
paddingX: designSystemTokens.spacing.spacing_1_1_2,
|
|
763
753
|
fontSize: theme.typography.pxToRem(14),
|
|
764
754
|
},
|
|
765
755
|
medium: {
|
|
766
756
|
height: designSystemTokens.spacing.spacing_5,
|
|
767
|
-
|
|
757
|
+
paddingX: designSystemTokens.spacing.spacing_2,
|
|
768
758
|
fontSize: theme.typography.pxToRem(14),
|
|
769
759
|
},
|
|
770
760
|
};
|
|
771
761
|
const sizeStyles = sizeConfig[size];
|
|
762
|
+
const paddingX = variant === 'tertiary' ? 0 : sizeStyles.paddingX;
|
|
763
|
+
const spinnerSize = size === 'small' ? designSystemTokens.iconSize.md : designSystemTokens.iconSize.xl;
|
|
764
|
+
const disabled = `&.${Button.buttonClasses.disabled}:not(.${Button.buttonClasses.loading})`;
|
|
772
765
|
// Base styles shared by all variants
|
|
773
766
|
const baseStyles = {
|
|
774
767
|
height: sizeStyles.height,
|
|
775
|
-
padding:
|
|
768
|
+
padding: `0 ${paddingX}px`,
|
|
769
|
+
fontFamily: 'inherit',
|
|
776
770
|
fontSize: sizeStyles.fontSize,
|
|
777
771
|
fontWeight: designSystemTokens.typography.fontWeight.semiBold,
|
|
772
|
+
letterSpacing: 'inherit',
|
|
778
773
|
lineHeight: '1.25rem',
|
|
779
774
|
borderRadius: designSystemTokens.borderRadius.button,
|
|
780
775
|
textTransform: 'none',
|
|
@@ -784,13 +779,56 @@ const StyledButtonBase$1 = styles.styled(ButtonBase, {
|
|
|
784
779
|
position: 'relative',
|
|
785
780
|
minWidth: 'fit-content',
|
|
786
781
|
gap: designSystemTokens.spacing.spacing_1,
|
|
782
|
+
// `gap` spaces the icons; MUI's slot margins would add to it
|
|
783
|
+
[`& .${Button.buttonClasses.startIcon}, & .${Button.buttonClasses.endIcon}`]: {
|
|
784
|
+
margin: 0,
|
|
785
|
+
},
|
|
786
|
+
// MUI sets font-size on the icon slot's first child; IconSlot takes it so 1em icons keep the label's size
|
|
787
|
+
[`& .${Button.buttonClasses.startIcon} > *:nth-of-type(1), & .${Button.buttonClasses.endIcon} > *:nth-of-type(1)`]: {
|
|
788
|
+
fontSize: 'inherit',
|
|
789
|
+
},
|
|
790
|
+
// MUI's indicator is a sibling of the icon; anchoring sizes and places it on the icon
|
|
791
|
+
[`&.${Button.buttonClasses.loadingPositionStart} .${Button.buttonClasses.startIcon}, &.${Button.buttonClasses.loadingPositionEnd} .${Button.buttonClasses.endIcon}`]: {
|
|
792
|
+
anchorName: '--mod-button-icon',
|
|
793
|
+
// MUI fades the icon out while the spinner appears at full opacity
|
|
794
|
+
transition: 'none',
|
|
795
|
+
},
|
|
796
|
+
[`&.${Button.buttonClasses.loadingPositionStart} .${Button.buttonClasses.loadingIndicator}, &.${Button.buttonClasses.loadingPositionEnd} .${Button.buttonClasses.loadingIndicator}`]: {
|
|
797
|
+
// MUI switches it to relative for fullWidth
|
|
798
|
+
position: 'absolute',
|
|
799
|
+
positionAnchor: '--mod-button-icon',
|
|
800
|
+
// Square on the icon's centre; the slot can be taller than the icon, and a non-square box wobbles
|
|
801
|
+
inset: 'auto auto auto anchor(left)',
|
|
802
|
+
alignSelf: 'anchor-center',
|
|
803
|
+
width: 'anchor-size(width)',
|
|
804
|
+
height: 'anchor-size(width)',
|
|
805
|
+
},
|
|
806
|
+
// Without anchor positioning, the spinner takes the standard icon size at the icon's edge
|
|
807
|
+
'@supports not (anchor-name: --a)': {
|
|
808
|
+
[`&.${Button.buttonClasses.loadingPositionStart} .${Button.buttonClasses.loadingIndicator}`]: {
|
|
809
|
+
inset: 'auto',
|
|
810
|
+
left: paddingX,
|
|
811
|
+
width: spinnerSize,
|
|
812
|
+
height: spinnerSize,
|
|
813
|
+
},
|
|
814
|
+
[`&.${Button.buttonClasses.loadingPositionEnd} .${Button.buttonClasses.loadingIndicator}`]: {
|
|
815
|
+
inset: 'auto',
|
|
816
|
+
right: paddingX,
|
|
817
|
+
width: spinnerSize,
|
|
818
|
+
height: spinnerSize,
|
|
819
|
+
},
|
|
820
|
+
},
|
|
821
|
+
// Hide the label at once when loading starts, so it doesn't fade out under the spinner
|
|
822
|
+
[`&.${Button.buttonClasses.loading}`]: {
|
|
823
|
+
transitionProperty: 'background-color, border-color',
|
|
824
|
+
},
|
|
787
825
|
// Disabled state (always show cursor)
|
|
788
|
-
[`&.${
|
|
826
|
+
[`&.${Button.buttonClasses.disabled}`]: {
|
|
789
827
|
cursor: 'not-allowed',
|
|
790
828
|
pointerEvents: 'auto',
|
|
791
829
|
},
|
|
792
830
|
// Focus visible for keyboard navigation
|
|
793
|
-
[`&.${
|
|
831
|
+
[`&.${Button.buttonClasses.focusVisible}`]: {
|
|
794
832
|
outline: `2px solid ${designSystemTokens.semanticColors.color.border.focus}`,
|
|
795
833
|
outlineOffset: 2,
|
|
796
834
|
},
|
|
@@ -807,14 +845,10 @@ const StyledButtonBase$1 = styles.styled(ButtonBase, {
|
|
|
807
845
|
'&:active': {
|
|
808
846
|
backgroundColor: designSystemTokens.semanticColors.button.primary.bgPressed,
|
|
809
847
|
},
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
:
|
|
813
|
-
|
|
814
|
-
backgroundColor: designSystemTokens.semanticColors.button.primary.bgDisabled,
|
|
815
|
-
color: designSystemTokens.semanticColors.button.fgDisabled,
|
|
816
|
-
},
|
|
817
|
-
}),
|
|
848
|
+
[disabled]: {
|
|
849
|
+
backgroundColor: designSystemTokens.semanticColors.button.primary.bgDisabled,
|
|
850
|
+
color: designSystemTokens.semanticColors.button.fgDisabled,
|
|
851
|
+
},
|
|
818
852
|
},
|
|
819
853
|
secondary: {
|
|
820
854
|
backgroundColor: designSystemTokens.semanticColors.button.secondary.bg,
|
|
@@ -826,15 +860,11 @@ const StyledButtonBase$1 = styles.styled(ButtonBase, {
|
|
|
826
860
|
'&:active': {
|
|
827
861
|
backgroundColor: designSystemTokens.semanticColors.button.secondary.bgPressed,
|
|
828
862
|
},
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
:
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
borderColor: designSystemTokens.semanticColors.color.border.primary,
|
|
835
|
-
color: designSystemTokens.semanticColors.button.fgDisabled,
|
|
836
|
-
},
|
|
837
|
-
}),
|
|
863
|
+
[disabled]: {
|
|
864
|
+
backgroundColor: designSystemTokens.semanticColors.button.secondary.bgDisabled,
|
|
865
|
+
borderColor: designSystemTokens.semanticColors.color.border.primary,
|
|
866
|
+
color: designSystemTokens.semanticColors.button.fgDisabled,
|
|
867
|
+
},
|
|
838
868
|
},
|
|
839
869
|
destructive: {
|
|
840
870
|
backgroundColor: designSystemTokens.semanticColors.button.destructive.bg,
|
|
@@ -847,20 +877,15 @@ const StyledButtonBase$1 = styles.styled(ButtonBase, {
|
|
|
847
877
|
backgroundColor: designSystemTokens.semanticColors.color.status.error.fg,
|
|
848
878
|
filter: 'brightness(0.9)',
|
|
849
879
|
},
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
:
|
|
853
|
-
|
|
854
|
-
backgroundColor: designSystemTokens.semanticColors.button.primary.bgDisabled,
|
|
855
|
-
color: designSystemTokens.semanticColors.button.fgDisabled,
|
|
856
|
-
},
|
|
857
|
-
}),
|
|
880
|
+
[disabled]: {
|
|
881
|
+
backgroundColor: designSystemTokens.semanticColors.button.primary.bgDisabled,
|
|
882
|
+
color: designSystemTokens.semanticColors.button.fgDisabled,
|
|
883
|
+
},
|
|
858
884
|
},
|
|
859
885
|
tertiary: {
|
|
860
886
|
backgroundColor: 'transparent',
|
|
861
887
|
color: designSystemTokens.semanticColors.color.text.input,
|
|
862
888
|
border: 'none',
|
|
863
|
-
padding: 0,
|
|
864
889
|
lineHeight: 1,
|
|
865
890
|
'&:hover': {
|
|
866
891
|
backgroundColor: 'transparent',
|
|
@@ -869,24 +894,26 @@ const StyledButtonBase$1 = styles.styled(ButtonBase, {
|
|
|
869
894
|
'&:active': {
|
|
870
895
|
color: designSystemTokens.semanticColors.button.tertiary.fgPressed,
|
|
871
896
|
},
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
:
|
|
875
|
-
|
|
876
|
-
backgroundColor: 'transparent',
|
|
877
|
-
color: designSystemTokens.semanticColors.button.tertiary.fgDisabled,
|
|
878
|
-
},
|
|
879
|
-
}),
|
|
897
|
+
[disabled]: {
|
|
898
|
+
backgroundColor: 'transparent',
|
|
899
|
+
color: designSystemTokens.semanticColors.button.tertiary.fgDisabled,
|
|
900
|
+
},
|
|
880
901
|
},
|
|
881
902
|
};
|
|
903
|
+
// MUI greys a loading button as disabled; keep the label in the variant's colour
|
|
904
|
+
const { color } = variantStyles[variant];
|
|
882
905
|
return {
|
|
883
906
|
...baseStyles,
|
|
884
907
|
...variantStyles[variant],
|
|
908
|
+
[`&.${Button.buttonClasses.loadingPositionStart}, &.${Button.buttonClasses.loadingPositionEnd}`]: { color },
|
|
885
909
|
};
|
|
886
910
|
});
|
|
911
|
+
const IconSlot = styles.styled('span')({
|
|
912
|
+
display: 'contents',
|
|
913
|
+
});
|
|
887
914
|
const LoadingSpinner = styles.styled(CircularProgress, {
|
|
888
|
-
shouldForwardProp: prop => prop !== '
|
|
889
|
-
})(({
|
|
915
|
+
shouldForwardProp: prop => prop !== 'buttonVariant',
|
|
916
|
+
})(({ buttonVariant }) => {
|
|
890
917
|
// Use appropriate spinner color for each variant to ensure visibility
|
|
891
918
|
const spinnerColors = {
|
|
892
919
|
primary: designSystemTokens.semanticColors.color.surface.raised,
|
|
@@ -895,14 +922,22 @@ const LoadingSpinner = styles.styled(CircularProgress, {
|
|
|
895
922
|
tertiary: designSystemTokens.semanticColors.button.tertiary.fg,
|
|
896
923
|
};
|
|
897
924
|
return {
|
|
898
|
-
color: spinnerColors[
|
|
925
|
+
color: spinnerColors[buttonVariant],
|
|
899
926
|
};
|
|
900
927
|
});
|
|
901
928
|
/**
|
|
902
|
-
* ModButton - Text button component based on MUI
|
|
929
|
+
* ModButton - Text button component based on MUI Button
|
|
903
930
|
*/
|
|
904
|
-
function ModButton({ variant = 'primary', size = 'medium', loading = false, children,
|
|
905
|
-
|
|
931
|
+
function ModButton({ variant = 'primary', size = 'medium', loading = false, children, startIcon, endIcon, ...rest }) {
|
|
932
|
+
const loadingPosition = startIcon ? 'start' : endIcon ? 'end' : 'center';
|
|
933
|
+
// Mirrors MUI: the spinner is named by the button, which gets an id while loading
|
|
934
|
+
const generatedId = react.useId();
|
|
935
|
+
const id = rest.id ?? (loading ? generatedId : undefined);
|
|
936
|
+
return (jsxRuntime.jsx(StyledButton, { buttonVariant: variant, buttonSize: size,
|
|
937
|
+
// Pinned so theme defaultProps or a ButtonGroup can't restyle it; ButtonBase had no focus ripple
|
|
938
|
+
variant: "text", size: "medium", color: "primary", disableFocusRipple: true, loading: loading, loadingPosition: loadingPosition, loadingIndicator: jsxRuntime.jsx(LoadingSpinner, { buttonVariant: variant,
|
|
939
|
+
// With an icon, the anchored indicator is the icon's size and the spinner fills it
|
|
940
|
+
size: loadingPosition === 'center' ? (size === 'small' ? designSystemTokens.iconSize.md : designSystemTokens.iconSize.xl) : '100%', "aria-labelledby": id }), startIcon: startIcon && jsxRuntime.jsx(IconSlot, { children: startIcon }), endIcon: endIcon && jsxRuntime.jsx(IconSlot, { children: endIcon }), "aria-busy": loading || undefined, ...rest, id: id, children: children }));
|
|
906
941
|
}
|
|
907
942
|
ModButton.displayName = 'ModButton';
|
|
908
943
|
|
|
@@ -939,8 +974,8 @@ const StyledButtonTab = styles.styled(MuiToggleButton)(({ theme }) => ({
|
|
|
939
974
|
* the Mui-selected class — we mirror that to aria-selected for tab semantics.
|
|
940
975
|
*/
|
|
941
976
|
function useTabAriaSync() {
|
|
942
|
-
const observerRef =
|
|
943
|
-
return
|
|
977
|
+
const observerRef = react.useRef(null);
|
|
978
|
+
return react.useCallback((node) => {
|
|
944
979
|
if (observerRef.current) {
|
|
945
980
|
observerRef.current.disconnect();
|
|
946
981
|
observerRef.current = null;
|
|
@@ -1764,9 +1799,9 @@ sx: _sx, theme: _theme, ...props }) => {
|
|
|
1764
1799
|
const apiRef = xDataGrid.useGridApiContext();
|
|
1765
1800
|
const columns = xDataGrid.useGridSelector(apiRef, xDataGrid.gridColumnDefinitionsSelector);
|
|
1766
1801
|
const columnVisibilityModel = xDataGrid.useGridSelector(apiRef, xDataGrid.gridColumnVisibilityModelSelector);
|
|
1767
|
-
const [searchText, setSearchText] =
|
|
1802
|
+
const [searchText, setSearchText] = react.useState('');
|
|
1768
1803
|
// Filter columns based on search
|
|
1769
|
-
const filteredColumns =
|
|
1804
|
+
const filteredColumns = react.useMemo(() => {
|
|
1770
1805
|
if (!searchText) {
|
|
1771
1806
|
return columns;
|
|
1772
1807
|
}
|
|
@@ -2205,7 +2240,7 @@ StyledGridFilterPanel.displayName = 'StyledGridFilterPanel';
|
|
|
2205
2240
|
* <ModDataGrid rows={rows} columns={columns} slots={{ baseSelect: ModDataGridSelect }} />
|
|
2206
2241
|
* ```
|
|
2207
2242
|
*/
|
|
2208
|
-
const ModDataGridSelect =
|
|
2243
|
+
const ModDataGridSelect = react.forwardRef(function ModDataGridSelect({ id, label, labelId, disabled, fullWidth, size, style, slotProps, material, onChange, onClose, onKeyDown, ...rest }, ref) {
|
|
2209
2244
|
const theme = styles.useTheme();
|
|
2210
2245
|
const hasLabel = label !== undefined;
|
|
2211
2246
|
// The grid omits `size` in edit cells, where MUI's adapter falls back to the theme's TextField
|
|
@@ -3552,13 +3587,13 @@ ModIconWrapper.displayName = 'ModIconWrapper';
|
|
|
3552
3587
|
function ModInfiniteScrollGrid({ onLoadMore, hasNextPage = true, loadMoreAtScrollPercent = 0.85, slots, slotProps: userSlotProps, sx: userSx, ...props }) {
|
|
3553
3588
|
const defaultApiRef = xDataGridPro.useGridApiRef();
|
|
3554
3589
|
const apiRef = props?.apiRef ? props.apiRef : defaultApiRef;
|
|
3555
|
-
const scrollerRef =
|
|
3556
|
-
const isLoadingRef =
|
|
3557
|
-
const [isScrolling, setIsScrolling] =
|
|
3558
|
-
const scrollTimeoutRef =
|
|
3590
|
+
const scrollerRef = react.useRef(null);
|
|
3591
|
+
const isLoadingRef = react.useRef(false);
|
|
3592
|
+
const [isScrolling, setIsScrolling] = react.useState(false);
|
|
3593
|
+
const scrollTimeoutRef = react.useRef(null);
|
|
3559
3594
|
// Infinite scroll handler
|
|
3560
3595
|
// Based on moderne-ui implementation
|
|
3561
|
-
|
|
3596
|
+
react.useEffect(() => {
|
|
3562
3597
|
if (!onLoadMore) {
|
|
3563
3598
|
return;
|
|
3564
3599
|
}
|
|
@@ -4704,10 +4739,10 @@ const ModNavigationAvatar = ({ children, ...props }) => {
|
|
|
4704
4739
|
};
|
|
4705
4740
|
ModNavigationAvatar.displayName = 'ModNavigationAvatar';
|
|
4706
4741
|
|
|
4707
|
-
const ModSideNavContext =
|
|
4742
|
+
const ModSideNavContext = react.createContext({
|
|
4708
4743
|
collapsed: false,
|
|
4709
4744
|
});
|
|
4710
|
-
const useModSideNav = () =>
|
|
4745
|
+
const useModSideNav = () => react.useContext(ModSideNavContext);
|
|
4711
4746
|
|
|
4712
4747
|
/**
|
|
4713
4748
|
* Variant color configuration
|
|
@@ -4943,11 +4978,11 @@ function ModPageContent({ pageTitle, subtitle, breadcrumbs, action, sticky = fal
|
|
|
4943
4978
|
const isFullBleed = layout === 'fullBleed';
|
|
4944
4979
|
const contentMaxWidth = isFullBleed ? false : contentMaxWidthProp;
|
|
4945
4980
|
const disableGutters = isFullBleed || disableGuttersProp;
|
|
4946
|
-
const [showBackToTopButton, setShowBackToTopButton] =
|
|
4947
|
-
const headerRef =
|
|
4948
|
-
const containerRef =
|
|
4981
|
+
const [showBackToTopButton, setShowBackToTopButton] = react.useState(false);
|
|
4982
|
+
const headerRef = react.useRef(null);
|
|
4983
|
+
const containerRef = react.useRef(null);
|
|
4949
4984
|
// Intersection observer for back to top button
|
|
4950
|
-
|
|
4985
|
+
react.useEffect(() => {
|
|
4951
4986
|
if (!showBackToTop || !headerRef.current) {
|
|
4952
4987
|
return;
|
|
4953
4988
|
}
|
|
@@ -5465,7 +5500,7 @@ const ModSelectField = ({ size = 'medium', destructive = false, label, required
|
|
|
5465
5500
|
ModSelectField.displayName = 'ModSelectField';
|
|
5466
5501
|
|
|
5467
5502
|
// Measure before paint so the fades don't flash; useEffect on the server.
|
|
5468
|
-
const useIsomorphicLayoutEffect = typeof window === 'undefined' ?
|
|
5503
|
+
const useIsomorphicLayoutEffect = typeof window === 'undefined' ? react.useEffect : react.useLayoutEffect;
|
|
5469
5504
|
const EXPANDED_WIDTH = 98;
|
|
5470
5505
|
const COLLAPSED_WIDTH = 68;
|
|
5471
5506
|
// The fade overlay must end on the same color as the rail to blend cleanly.
|
|
@@ -5595,14 +5630,14 @@ const Handle = styles.styled(ButtonBase)(({ theme }) => ({
|
|
|
5595
5630
|
* Attach both `ref` and `onScroll` to the scroll element.
|
|
5596
5631
|
*/
|
|
5597
5632
|
function useScrollEdges() {
|
|
5598
|
-
const ref =
|
|
5599
|
-
const contentRef =
|
|
5633
|
+
const ref = react.useRef(null);
|
|
5634
|
+
const contentRef = react.useRef(null);
|
|
5600
5635
|
// Both start hidden; the layout effect corrects them before first paint.
|
|
5601
|
-
const [edges, setEdges] =
|
|
5636
|
+
const [edges, setEdges] = react.useState({
|
|
5602
5637
|
canScrollUp: false,
|
|
5603
5638
|
canScrollDown: false,
|
|
5604
5639
|
});
|
|
5605
|
-
const measure =
|
|
5640
|
+
const measure = react.useCallback(() => {
|
|
5606
5641
|
const el = ref.current;
|
|
5607
5642
|
if (!el) {
|
|
5608
5643
|
return;
|
|
@@ -5619,7 +5654,7 @@ function useScrollEdges() {
|
|
|
5619
5654
|
// Mount only; later changes come via the observer or onScroll.
|
|
5620
5655
|
useIsomorphicLayoutEffect(measure, [measure]);
|
|
5621
5656
|
// Resizes fire no scroll event: watch the viewport box and the content box.
|
|
5622
|
-
|
|
5657
|
+
react.useEffect(() => {
|
|
5623
5658
|
const el = ref.current;
|
|
5624
5659
|
// Absent in jsdom; without it only resize tracking is lost.
|
|
5625
5660
|
if (!el || typeof ResizeObserver === 'undefined') {
|
|
@@ -5652,7 +5687,7 @@ function useScrollEdges() {
|
|
|
5652
5687
|
* pattern.
|
|
5653
5688
|
*/
|
|
5654
5689
|
function ModSideNav({ collapsed, onCollapsedChange, header, footer, children, className, id, 'aria-label': ariaLabel, }) {
|
|
5655
|
-
const contextValue =
|
|
5690
|
+
const contextValue = react.useMemo(() => ({ collapsed }), [collapsed]);
|
|
5656
5691
|
const { ref: scrollRef, contentRef, onScroll, canScrollUp, canScrollDown } = useScrollEdges();
|
|
5657
5692
|
const HandleIcon = collapsed ? lucideReact.ChevronRight : lucideReact.ChevronLeft;
|
|
5658
5693
|
return (jsxRuntime.jsx(ModSideNavContext.Provider, { value: contextValue, children: jsxRuntime.jsxs(Frame, { collapsed: collapsed, children: [jsxRuntime.jsxs(Root, { collapsed: collapsed, "aria-label": ariaLabel, className: className, id: id, children: [jsxRuntime.jsxs(HeaderRegion, { children: [header, jsxRuntime.jsx(Fade, { edge: "header", visible: canScrollUp })] }), jsxRuntime.jsx(Scroll, { ref: scrollRef, onScroll: onScroll, "data-testid": "mod-side-nav-scroll", children: jsxRuntime.jsx(Stack, { ref: contentRef, sx: {
|
|
@@ -6272,8 +6307,8 @@ const ModToggleButtonGroup = ({ size = 'medium', variant = 'default', children,
|
|
|
6272
6307
|
// Forward size and variant to each ModToggleButton child so consumers don't
|
|
6273
6308
|
// have to set them on every button. MUI's group already does this via
|
|
6274
6309
|
// context for its own size prop, but our shapes don't pass through unchanged.
|
|
6275
|
-
const sized =
|
|
6276
|
-
?
|
|
6310
|
+
const sized = react.Children.map(children, child => react.isValidElement(child) && child.type === ModToggleButton
|
|
6311
|
+
? react.cloneElement(child, { size, variant })
|
|
6277
6312
|
: child);
|
|
6278
6313
|
return (jsxRuntime.jsx(StyledToggleButtonGroup$1, { groupVariant: variant, ...props, children: sized }));
|
|
6279
6314
|
};
|
|
@@ -6351,7 +6386,7 @@ const ModTreeItemLabel = (props) => {
|
|
|
6351
6386
|
*
|
|
6352
6387
|
* Slot data is read from the item model (passed via `items` on ModTreeView).
|
|
6353
6388
|
*/
|
|
6354
|
-
const ModTreeItem =
|
|
6389
|
+
const ModTreeItem = react.forwardRef(function ModTreeItem({ slots, slotProps, ...props }, ref) {
|
|
6355
6390
|
return (jsxRuntime.jsx(TreeItem.TreeItem, { ref: ref, slots: { label: ModTreeItemLabel, ...slots },
|
|
6356
6391
|
// itemId is not in MUI's label slot type but ModTreeItemLabel needs it for useTreeItemModel
|
|
6357
6392
|
slotProps: {
|