From f1de1f4566e79e61bbfa906e82e57ff17d448686 Mon Sep 17 00:00:00 2001 From: Denis Yakshov Date: Mon, 5 Oct 2026 13:41:47 +0200 Subject: [PATCH] feat(react): migrate to ref-as-prop --- packages/react/MIGRATION.md | 2 +- packages/react/src/components/Alert/Alert.tsx | 5 +- .../Alert/AlertActions/AlertActions.tsx | 6 +- .../Alert/AlertClose/AlertClose.tsx | 5 +- .../Alert/AlertTitle/AlertTitle.tsx | 6 +- .../react/src/components/AppBar/AppBar.tsx | 9 +- .../components/AudioPlayer/AudioPlayer.tsx | 6 +- .../components/Autocomplete/Autocomplete.tsx | 8 +- .../AutocompleteField/AutocompleteField.tsx | 8 +- .../AutocompleteMenu/AutocompleteMenu.tsx | 12 +- .../AutocompleteMenuFooter.tsx | 9 +- .../AutocompleteMenuHeader.tsx | 9 +- .../react/src/components/Avatar/Avatar.tsx | 5 +- .../components/AvatarGroup/AvatarGroup.tsx | 5 +- .../src/components/Backdrop/Backdrop.tsx | 6 +- packages/react/src/components/Badge/Badge.tsx | 3 +- .../BadgePlacementControl.tsx | 8 +- .../react/src/components/Banner/Banner.tsx | 5 +- .../Banner/BannerActions/BannerActions.tsx | 6 +- .../Banner/BannerTitle/BannerTitle.tsx | 6 +- .../components/BottomSheet/BottomSheet.tsx | 6 +- .../Breadcrumbs/Breadcrumb/Breadcrumb.tsx | 3 +- .../react/src/components/Button/Button.tsx | 5 +- .../src/components/ButtonBase/ButtonBase.tsx | 4 +- .../src/components/Calendar/Calendar.tsx | 6 +- .../CalendarButton/CalendarButton.tsx | 5 +- .../Calendar/CalendarHead/CalendarHead.tsx | 6 +- .../src/components/Checkbox/Checkbox.tsx | 4 +- .../Checkbox/CheckboxIcon/CheckboxIcon.tsx | 6 +- packages/react/src/components/Chip/Chip.tsx | 12 +- packages/react/src/components/Chips/Chips.tsx | 10 +- .../components/ClearButton/ClearButton.tsx | 5 +- .../src/components/Collapse/Collapse.tsx | 61 ++- .../src/components/DateInput/DateInput.tsx | 9 +- .../react/src/components/Dialog/Dialog.tsx | 6 +- .../Dialog/DialogActions/DialogActions.tsx | 5 +- .../Dialog/DialogArrow/DialogArrow.tsx | 6 +- .../Dialog/DialogClose/DialogClose.tsx | 6 +- .../Dialog/DialogContent/DialogContent.tsx | 6 +- .../Dialog/DialogTitle/DialogTitle.tsx | 5 +- .../react/src/components/Divider/Divider.tsx | 5 +- .../react/src/components/Drawer/Drawer.tsx | 12 +- .../DropzoneCompact/DropzoneCompact.tsx | 6 +- .../src/components/EmptyState/EmptyState.tsx | 6 +- .../EmptyStateCompact/EmptyStateCompact.tsx | 6 +- .../src/components/ErrorPage/ErrorPage.tsx | 6 +- .../ErrorPageActions/ErrorPageActions.tsx | 6 +- .../ErrorPageDescription.tsx | 9 +- .../ErrorPageFooter/ErrorPageFooter.tsx | 6 +- .../ErrorPageHeading/ErrorPageHeading.tsx | 6 +- .../ErrorPage/ErrorPageLogo/ErrorPageLogo.tsx | 6 +- .../ErrorPageStatus/ErrorPageStatus.tsx | 6 +- packages/react/src/components/Fade/Fade.tsx | 10 +- .../src/components/FileIcon/FileIcon.tsx | 8 +- .../src/components/FileIcon/FileIcon.types.ts | 6 +- .../FileIcon/FileIconBadge/FileIconBadge.tsx | 5 +- .../FileIcon/FileIconText/FileIconText.tsx | 6 +- .../FileIcon/icons/FileIconIcon.tsx | 7 +- .../FileIcon/icons/FileIconIconVariant.tsx | 53 +- .../src/components/FileInfo/FileInfo.tsx | 6 +- .../FileInfoContent/FileInfoContent.tsx | 6 +- .../FileInfo/FileInfoMeta/FileInfoMeta.tsx | 6 +- .../FileInfoMetaSeparator.tsx | 9 +- .../FileInfo/FileInfoName/FileInfoName.tsx | 6 +- .../react/src/components/Filters/Filters.tsx | 6 +- .../Filters/FiltersContent/FiltersContent.tsx | 6 +- .../Filters/FiltersFilter/FiltersFilter.tsx | 6 +- .../Filters/FiltersFooter/FiltersFooter.tsx | 6 +- .../FiltersFormControlLabel.tsx | 8 +- .../FiltersFormGroup/FiltersFormGroup.tsx | 6 +- .../Filters/FiltersHeader/FiltersHeader.tsx | 6 +- .../FormControlLabel/FormControlLabel.tsx | 5 +- .../components/FormField/FormField.context.ts | 4 +- .../src/components/FormField/FormField.tsx | 6 +- .../FormFieldAdornment/FormFieldAdornment.tsx | 9 +- .../FormFieldField/FormFieldField.tsx | 9 +- .../FormFieldHelperText.tsx | 9 +- .../FormFieldInput/FormFieldInput.tsx | 11 +- .../FormFieldLabel/FormFieldLabel.tsx | 9 +- .../react/src/components/Gallery/Gallery.tsx | 5 +- .../Gallery/GalleryActions/GalleryActions.tsx | 6 +- .../GalleryActionsButton.tsx | 5 +- .../GalleryActionsButtonGroup.tsx | 9 +- .../GalleryDescription/GalleryDescription.tsx | 12 +- .../Gallery/GalleryMeta/GalleryMeta.tsx | 6 +- .../GalleryMetaSeparator.tsx | 9 +- .../GalleryMetaText/GalleryMetaText.tsx | 5 +- .../Gallery/GalleryPanel/GalleryPanel.tsx | 9 +- .../Gallery/GallerySwiper/GallerySwiper.tsx | 6 +- .../GallerySwiperImage/GallerySwiperImage.tsx | 6 +- .../GalleryThumbnails/GalleryThumbnails.tsx | 10 +- .../GalleryThumbnailsImage.tsx | 9 +- .../GalleryThumbnailsItem.tsx | 8 +- .../Gallery/GalleryTooltip/GalleryTooltip.tsx | 5 +- packages/react/src/components/Grow/Grow.tsx | 16 +- .../src/components/ImageZoom/ImageZoom.tsx | 8 +- .../InformationIcon/InformationIcon.tsx | 10 +- packages/react/src/components/Kbd/Kbd.tsx | 5 +- .../LinearProgress/LinearProgress.tsx | 9 +- packages/react/src/components/Link/Link.tsx | 3 +- .../src/components/ListItem/ListItem.tsx | 6 +- .../ListItem/ListItemIcon/ListItemIcon.tsx | 6 +- .../ListItem/ListItemText/ListItemText.tsx | 5 +- .../LoadingButton/LoadingButton.tsx | 6 +- .../react/src/components/MadeBy/MadeBy.tsx | 3 +- packages/react/src/components/Menu/Menu.tsx | 6 +- .../src/components/Menu/MenuList/MenuList.tsx | 6 +- .../src/components/MenuGroup/MenuGroup.tsx | 5 +- .../src/components/MenuItem/MenuItem.tsx | 6 +- packages/react/src/components/Modal/Modal.tsx | 6 +- .../src/components/Modal/useModal.types.ts | 2 +- .../OverlayScrollbars/OverlayScrollbars.tsx | 14 +- .../src/components/PageHGroup/PageHGroup.tsx | 6 +- .../PageHGroupActions/PageHGroupActions.tsx | 6 +- .../PageHGroupBreadcrumbs.tsx | 9 +- .../PageHGroupHeading/PageHGroupHeading.tsx | 6 +- .../PageHGroupMain/PageHGroupMain.tsx | 6 +- .../PageHGroupStatus/PageHGroupStatus.tsx | 6 +- .../src/components/Pagination/Pagination.tsx | 9 +- .../PaginationPages/PaginationPages.tsx | 9 +- .../PaginationRange/PaginationRange.tsx | 9 +- .../PasswordField/PasswordField.tsx | 3 +- .../src/components/PhoneField/PhoneField.tsx | 12 +- .../react/src/components/Popover/Popover.tsx | 6 +- .../react/src/components/Popper/Popper.tsx | 10 +- .../react/src/components/Portal/Portal.tsx | 6 +- packages/react/src/components/Price/Price.tsx | 10 +- .../src/components/Property/Property.tsx | 5 +- packages/react/src/components/Radio/Radio.tsx | 4 +- .../components/Radio/RadioIcon/RadioIcon.tsx | 6 +- .../src/components/RadioGroup/RadioGroup.tsx | 7 +- .../components/RibbonBadge/RibbonBadge.tsx | 3 +- packages/react/src/components/SFS/SFS.tsx | 6 +- .../components/SFS/SFSButton/SFSButton.tsx | 6 +- .../src/components/SFS/SFSChips/SFSChips.tsx | 6 +- .../components/SFS/SFSFilters/SFSFilters.tsx | 9 +- .../SFS/SFSFiltersGroup/SFSFiltersGroup.tsx | 6 +- .../src/components/SFS/SFSRow/SFSRow.tsx | 6 +- .../components/SFS/SFSSearch/SFSSearch.tsx | 6 +- .../components/SFS/SFSSorting/SFSSorting.tsx | 9 +- .../react/src/components/Search/Search.tsx | 5 +- .../react/src/components/Sidebar/Sidebar.tsx | 3 +- .../Sidebar/SidebarDivider/SidebarDivider.tsx | 6 +- .../Sidebar/SidebarItem/SidebarItem.tsx | 7 +- .../Sidebar/SidebarMenu/SidebarMenu.tsx | 6 +- .../SidebarScrollable/SidebarScrollable.tsx | 12 +- .../Sidebar/SidebarSpacer/SidebarSpacer.tsx | 6 +- .../Sidebar/SidebarToggle/SidebarToggle.tsx | 6 +- .../react/src/components/Sidenav/Sidenav.tsx | 4 +- .../Sidenav/SidenavItem/SidenavItem.tsx | 6 +- packages/react/src/components/Slide/Slide.tsx | 10 +- .../react/src/components/Slider/Slider.tsx | 6 +- .../src/components/Snackbar/Snackbar.tsx | 6 +- .../Snackbar/SnackbarClose/SnackbarClose.tsx | 6 +- .../components/SortingMenu/SortingMenu.tsx | 8 +- .../SpinnerDashRing/SpinnerDashRing.tsx | 5 +- .../SpinnerFadingBars/SpinnerFadingBars.tsx | 5 +- .../SpinnerFadingDots/SpinnerFadingDots.tsx | 5 +- .../SpinnerFadingDoubleRing.tsx | 5 +- .../SpinnerFadingRing/SpinnerFadingRing.tsx | 5 +- .../Spinner/SpinnerRing/SpinnerRing.tsx | 5 +- .../Swiper/SwiperButton/SwiperButton.tsx | 5 +- .../SwiperPagination/SwiperPagination.tsx | 5 +- .../SwiperPaginationItem.tsx | 6 +- .../react/src/components/Switch/Switch.tsx | 5 +- .../src/components/SwitchBase/SwitchBase.tsx | 14 +- .../components/SwitchBase/SwitchBase.types.ts | 5 - .../react/src/components/TabBar/TabBar.tsx | 6 +- .../TabBar/TabBarItem/TabBarItem.tsx | 3 +- packages/react/src/components/Table/Table.tsx | 68 ++- .../Table/TableActions/TableActions.tsx | 33 +- .../components/Table/TableBody/TableBody.tsx | 72 ++- .../components/Table/TableCell/TableCell.tsx | 503 +++++++++--------- .../components/Table/TableFoot/TableFoot.tsx | 87 +-- .../components/Table/TableHead/TableHead.tsx | 103 ++-- .../components/Table/TableItem/TableItem.tsx | 6 +- .../components/Table/TableRow/TableRow.tsx | 69 ++- .../Table/TableScrollbar/TableScrollbar.tsx | 39 +- .../components/Table/TableText/TableText.tsx | 88 ++- .../src/components/Table/useTableResize.ts | 6 +- .../components/Table/useTableStickyOffset.ts | 4 +- .../react/src/components/Tabs/Tab/Tab.tsx | 6 +- .../src/components/Tabs/Tab/Tab.types.ts | 5 - .../Tabs/TabScrollButton/TabScrollButton.tsx | 9 +- packages/react/src/components/Tabs/Tabs.tsx | 6 +- packages/react/src/components/Tag/Tag.tsx | 5 +- .../src/components/TextField/TextField.tsx | 6 +- .../TextFieldGroup/TextFieldGroup.tsx | 5 +- .../react/src/components/Tooltip/Tooltip.tsx | 55 +- .../TooltipEllipsis/TooltipEllipsis.types.ts | 7 +- .../components/TouchRipple/TouchRipple.tsx | 6 +- packages/react/src/components/Tour/Tour.tsx | 10 +- packages/react/src/components/Zoom/Zoom.tsx | 10 +- .../react/src/hooks/useForkRef/useForkRef.ts | 2 +- .../useIsFocusVisible/useIsFocusVisible.ts | 4 +- .../react/src/hooks/useMenuAim/useMenuAim.ts | 4 +- .../react/src/hooks/useSticky/useSticky.ts | 4 +- ...Callbacks.ts => useTransitionCallbacks.ts} | 2 +- packages/react/src/utils/setRef.ts | 4 +- 199 files changed, 1346 insertions(+), 1101 deletions(-) rename packages/react/src/transitions/{transitionCallbacks.ts => useTransitionCallbacks.ts} (87%) diff --git a/packages/react/MIGRATION.md b/packages/react/MIGRATION.md index 005ae1055..2f3d7a491 100644 --- a/packages/react/MIGRATION.md +++ b/packages/react/MIGRATION.md @@ -31,7 +31,7 @@ npm install --save-dev @types/react@^19 @types/react-dom@^19 ``` Follow the [official React 19 upgrade guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) for the changes -it requires in your own code. The components and hooks of the library keep their current API. +it requires in your own code. ## 0.16.0 → 0.17.0 diff --git a/packages/react/src/components/Alert/Alert.tsx b/packages/react/src/components/Alert/Alert.tsx index 39c5dc384..8e4ce6476 100644 --- a/packages/react/src/components/Alert/Alert.tsx +++ b/packages/react/src/components/Alert/Alert.tsx @@ -1,5 +1,7 @@ 'use client'; +import { RefAttributes } from 'react'; + import { AlertProps } from './Alert.types'; import clsx from 'clsx'; @@ -17,7 +19,7 @@ const defaultIconMapping = { /** * An alert displays a short, important message in a way that attracts the user's attention without interrupting the user's task. */ -export const Alert = (inProps: AlertProps) => { +export const Alert = ({ ref, ...inProps }: AlertProps & RefAttributes) => { const { className, children, @@ -38,6 +40,7 @@ export const Alert = (inProps: AlertProps) => { return (
{ +export const AlertActions = ({ ref, ...inProps }: AlertActionsProps & RefAttributes) => { const { className, children, style } = useDefaultProps({ props: inProps, name: 'ESAlertActions', }); return ( -
+
{children}
); diff --git a/packages/react/src/components/Alert/AlertClose/AlertClose.tsx b/packages/react/src/components/Alert/AlertClose/AlertClose.tsx index 5d1e82957..e63fa4dcb 100644 --- a/packages/react/src/components/Alert/AlertClose/AlertClose.tsx +++ b/packages/react/src/components/Alert/AlertClose/AlertClose.tsx @@ -1,5 +1,7 @@ 'use client'; +import { RefAttributes } from 'react'; + import { AlertCloseProps } from './AlertClose.types'; import clsx from 'clsx'; @@ -11,7 +13,7 @@ import { Button } from '../../Button'; /** * @see `Alert` */ -export const AlertClose = (inProps: AlertCloseProps) => { +export const AlertClose = ({ ref, ...inProps }: AlertCloseProps & RefAttributes) => { const { className, style, @@ -27,6 +29,7 @@ export const AlertClose = (inProps: AlertCloseProps) => { return (
- - {editable && !editing && ( -
- {iconEdit} -
- )} - - {editing && ( -
- - -
- )}
- ); - }) -); + + {editable && !editing && ( +
{iconEdit}
+ )} + + {editing && ( +
+ + +
+ )} + + ); +}); diff --git a/packages/react/src/components/Table/TableFoot/TableFoot.tsx b/packages/react/src/components/Table/TableFoot/TableFoot.tsx index c2834c947..7bcabac7b 100644 --- a/packages/react/src/components/Table/TableFoot/TableFoot.tsx +++ b/packages/react/src/components/Table/TableFoot/TableFoot.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef, memo, useRef, useState } from 'react'; +import { memo, RefAttributes, useRef, useState } from 'react'; import { TableFootProps } from './TableFoot.types'; @@ -12,45 +12,46 @@ import { useDefaultProps } from '../../../theming'; /** * @see `Table` */ -export const TableFoot = memo( - forwardRef(function TableFoot(inProps, inRef) { - const { children, className, sticky, style } = useDefaultProps({ - props: inProps, - name: 'ESTableFoot', - }); - - const [isStuck, setStuck] = useState(false); - - const ref = useRef(null); - - const rootRef = useForkRef(ref, inRef); - - useIntersectionObserver( - ref, - (entries) => { - setStuck(entries[0].intersectionRatio < 1); - }, - { threshold: [1], rootMargin: `0px 0px -${(sticky || 0) + 1}px` } - ); - - return ( -
- {children} -
- ); - }) -); +export const TableFoot = memo(function TableFoot({ + ref: inRef, + ...inProps +}: TableFootProps & RefAttributes) { + const { children, className, sticky, style } = useDefaultProps({ + props: inProps, + name: 'ESTableFoot', + }); + + const [isStuck, setStuck] = useState(false); + + const ref = useRef(null); + + const rootRef = useForkRef(ref, inRef); + + useIntersectionObserver( + ref, + (entries) => { + setStuck(entries[0].intersectionRatio < 1); + }, + { threshold: [1], rootMargin: `0px 0px -${(sticky || 0) + 1}px` } + ); + + return ( +
+ {children} +
+ ); +}); diff --git a/packages/react/src/components/Table/TableHead/TableHead.tsx b/packages/react/src/components/Table/TableHead/TableHead.tsx index 0fae36251..0b759137c 100644 --- a/packages/react/src/components/Table/TableHead/TableHead.tsx +++ b/packages/react/src/components/Table/TableHead/TableHead.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef, memo, useMemo, useState } from 'react'; +import { memo, RefAttributes, useMemo, useState } from 'react'; import { TableHeadProps } from './TableHead.types'; @@ -17,58 +17,59 @@ const TABLE_CELL_CONTEXT_VALUE = { variant: 'head' as const }; /** * @see `Table` */ -export const TableHead = memo( - forwardRef(function TableHead(inProps, inRef) { - const { - children, - className, - sticky, - style, - rowDividers = true, - colDividers = false, - } = useDefaultProps({ - props: inProps, - name: 'ESTableHead', - }); +export const TableHead = memo(function TableHead({ + ref: inRef, + ...inProps +}: TableHeadProps & RefAttributes) { + const { + children, + className, + sticky, + style, + rowDividers = true, + colDividers = false, + } = useDefaultProps({ + props: inProps, + name: 'ESTableHead', + }); - const [isStuck, setStuck] = useState(false); + const [isStuck, setStuck] = useState(false); - const { ref, setRef } = useTableHeadContext(); - const rootRef = useForkRef(setRef, inRef); + const { ref, setRef } = useTableHeadContext(); + const rootRef = useForkRef(setRef, inRef); - useIntersectionObserver( - { current: ref }, - (entries) => { - setStuck(entries[0].intersectionRatio < 1); - }, - { threshold: [1], rootMargin: `-${(sticky || 0) + 1}px 0px 0px` } - ); + useIntersectionObserver( + { current: ref }, + (entries) => { + setStuck(entries[0].intersectionRatio < 1); + }, + { threshold: [1], rootMargin: `-${(sticky || 0) + 1}px 0px 0px` } + ); - const value = useMemo(() => { - return { ...TABLE_CELL_CONTEXT_VALUE, rowDividers, colDividers }; - }, [rowDividers, colDividers]); + const value = useMemo(() => { + return { ...TABLE_CELL_CONTEXT_VALUE, rowDividers, colDividers }; + }, [rowDividers, colDividers]); - return ( - -
-
{children}
-
-
- ); - }) -); + return ( + +
+
{children}
+
+
+ ); +}); diff --git a/packages/react/src/components/Table/TableItem/TableItem.tsx b/packages/react/src/components/Table/TableItem/TableItem.tsx index 72db2118e..203870a8d 100644 --- a/packages/react/src/components/Table/TableItem/TableItem.tsx +++ b/packages/react/src/components/Table/TableItem/TableItem.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef } from 'react'; +import { RefAttributes } from 'react'; import { TableItemProps } from './TableItem.types'; @@ -11,7 +11,7 @@ import { useDefaultProps } from '../../../theming'; /** * @see `Table` */ -export const TableItem = forwardRef(function TableItem(inProps, ref) { +export const TableItem = ({ ref, ...inProps }: TableItemProps & RefAttributes) => { const { className, style, avatar, primary, secondary } = useDefaultProps({ props: inProps, name: 'ESTableItem', @@ -26,4 +26,4 @@ export const TableItem = forwardRef(function Tab ); -}); +}; diff --git a/packages/react/src/components/Table/TableRow/TableRow.tsx b/packages/react/src/components/Table/TableRow/TableRow.tsx index 7c4ddb273..305855fa0 100644 --- a/packages/react/src/components/Table/TableRow/TableRow.tsx +++ b/packages/react/src/components/Table/TableRow/TableRow.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef, memo } from 'react'; +import { memo } from 'react'; import { TableRowProps, TableRowTypeMap } from './TableRow.types'; @@ -13,43 +13,36 @@ import { useTableContext } from '../Table.context'; /** * @see `Table` */ -export const TableRow = memo( - forwardRef(function TableRow(inProps: TableRowProps, ref) { - const { - component: Component = 'div', - children, - className, - style, - selected, - hover, - ...props - } = useDefaultProps({ - props: inProps, - name: 'ESTableRow', - }); +export const TableRow = memo(function TableRow({ ref, ...inProps }: TableRowProps) { + const { + component: Component = 'div', + children, + className, + style, + selected, + hover, + ...props + } = useDefaultProps({ + props: inProps, + name: 'ESTableRow', + }); - const { columns } = useTableContext(); + const { columns } = useTableContext(); - return ( -
+ - - {children} - -
- ); - }) -) as OverridableComponent; + {children} + + + ); +}) as OverridableComponent; diff --git a/packages/react/src/components/Table/TableScrollbar/TableScrollbar.tsx b/packages/react/src/components/Table/TableScrollbar/TableScrollbar.tsx index 0ed561b46..60d6c0072 100644 --- a/packages/react/src/components/Table/TableScrollbar/TableScrollbar.tsx +++ b/packages/react/src/components/Table/TableScrollbar/TableScrollbar.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef, memo } from 'react'; +import { memo, RefAttributes } from 'react'; import { TableScrollbarProps } from './TableScrollbar.types'; @@ -14,21 +14,22 @@ import { useDefaultProps } from '../../../theming'; /** * @see `Table` */ -export const TableScrollbar = memo( - forwardRef(function TableScrollbar(inProps, inRef) { - const { className, style } = useDefaultProps({ - props: inProps, - name: 'ESTableScrollbar', - }); - - const { width, setRef } = useTableScrollbarContext(); - - const rootRef = useForkRef(setRef, inRef); - - return ( -
-
-
- ); - }) -); +export const TableScrollbar = memo(function TableScrollbar({ + ref: inRef, + ...inProps +}: TableScrollbarProps & RefAttributes) { + const { className, style } = useDefaultProps({ + props: inProps, + name: 'ESTableScrollbar', + }); + + const { width, setRef } = useTableScrollbarContext(); + + const rootRef = useForkRef(setRef, inRef); + + return ( +
+
+
+ ); +}); diff --git a/packages/react/src/components/Table/TableText/TableText.tsx b/packages/react/src/components/Table/TableText/TableText.tsx index f42640fc1..55497bdd3 100644 --- a/packages/react/src/components/Table/TableText/TableText.tsx +++ b/packages/react/src/components/Table/TableText/TableText.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef, memo, MutableRefObject } from 'react'; +import { memo, RefAttributes, RefObject } from 'react'; import { TableTextProps } from './TableText.types'; @@ -12,52 +12,46 @@ import { TooltipEllipsis } from '../../TooltipEllipsis'; /** * @see `Table` */ -export const TableText = memo( - forwardRef(function TableText(inProps, ref) { - const { - children, - className, - style, - tooltip = true, - TooltipProps, - } = useDefaultProps({ - props: inProps, - name: 'ESTableText', - }); - - if (tooltip) { - return ( - - {({ ref }) => ( -
} - className={clsx('es-table-text', className)} - style={style} - > - {children} -
- )} -
- ); - } +export const TableText = memo(function TableText({ ref, ...inProps }: TableTextProps & RefAttributes) { + const { + children, + className, + style, + tooltip = true, + TooltipProps, + } = useDefaultProps({ + props: inProps, + name: 'ESTableText', + }); + if (tooltip) { return ( -
- {children} -
+ + {({ ref }) => ( +
} className={clsx('es-table-text', className)} style={style}> + {children} +
+ )} +
); - }) -); + } + + return ( +
+ {children} +
+ ); +}); diff --git a/packages/react/src/components/Table/useTableResize.ts b/packages/react/src/components/Table/useTableResize.ts index 43140c4a0..e9ea7db0c 100644 --- a/packages/react/src/components/Table/useTableResize.ts +++ b/packages/react/src/components/Table/useTableResize.ts @@ -1,6 +1,6 @@ 'use client'; -import { Dispatch, MutableRefObject, SetStateAction } from 'react'; +import { Dispatch, RefObject, SetStateAction } from 'react'; /** * The hook that manages resizing of the table columns. @@ -11,8 +11,8 @@ import { Dispatch, MutableRefObject, SetStateAction } from 'react'; * @returns The `onResize` and `onResizeCommit` functions taking column index and colSpan and returning callbacks for the corresponding `TableCell`. */ export const useTableResize = ( - ref: MutableRefObject, - rowRef: MutableRefObject, + ref: RefObject, + rowRef: RefObject, columns: string[], setColumns: Dispatch> ) => { diff --git a/packages/react/src/components/Table/useTableStickyOffset.ts b/packages/react/src/components/Table/useTableStickyOffset.ts index 726e9914d..36523a49d 100644 --- a/packages/react/src/components/Table/useTableStickyOffset.ts +++ b/packages/react/src/components/Table/useTableStickyOffset.ts @@ -1,6 +1,6 @@ 'use client'; -import { MutableRefObject, useEffect } from 'react'; +import { RefObject, useEffect } from 'react'; const getStickyOffset = (element: HTMLElement | null, pin: 'left' | 'right') => { let width = 0; @@ -38,7 +38,7 @@ const getStickyOffset = (element: HTMLElement | null, pin: 'left' | 'right') => * @internal * The hook that sets left and right offsets for sticky (pinned) cells. */ -export const useTableStickyOffset = (ref: MutableRefObject) => { +export const useTableStickyOffset = (ref: RefObject) => { useEffect(() => { if (ref.current) { const resizeObserver = new ResizeObserver(() => { diff --git a/packages/react/src/components/Tabs/Tab/Tab.tsx b/packages/react/src/components/Tabs/Tab/Tab.tsx index 803aaf7e2..50ebc4604 100644 --- a/packages/react/src/components/Tabs/Tab/Tab.tsx +++ b/packages/react/src/components/Tabs/Tab/Tab.tsx @@ -1,6 +1,6 @@ 'use client'; -import { FocusEvent, forwardRef, MouseEvent } from 'react'; +import { FocusEvent, MouseEvent, RefAttributes } from 'react'; import { TabProps } from './Tab.types'; @@ -12,7 +12,7 @@ import { ButtonBase } from '../../ButtonBase'; /** * @see `Tabs` */ -export const Tab = forwardRef(function Tab(inProps: TabProps, ref) { +export const Tab = ({ ref, ...inProps }: TabProps & RefAttributes) => { const { className, disabled = false, @@ -77,4 +77,4 @@ export const Tab = forwardRef(function Tab(inProps: {indicator} ); -}); +}; diff --git a/packages/react/src/components/Tabs/Tab/Tab.types.ts b/packages/react/src/components/Tabs/Tab/Tab.types.ts index f2b64e4ee..88b971753 100644 --- a/packages/react/src/components/Tabs/Tab/Tab.types.ts +++ b/packages/react/src/components/Tabs/Tab/Tab.types.ts @@ -11,11 +11,6 @@ export interface TabProps { * @default false */ disabled?: boolean; - /** - * If `true`, the keyboard focus ripple is disabled. - * @default true - */ - disableFocusRipple?: boolean; /** * The label element. */ diff --git a/packages/react/src/components/Tabs/TabScrollButton/TabScrollButton.tsx b/packages/react/src/components/Tabs/TabScrollButton/TabScrollButton.tsx index 82f65b049..02a01c314 100644 --- a/packages/react/src/components/Tabs/TabScrollButton/TabScrollButton.tsx +++ b/packages/react/src/components/Tabs/TabScrollButton/TabScrollButton.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef } from 'react'; +import { RefAttributes } from 'react'; import { TabScrollButtonProps } from './TabScrollButton.types'; @@ -14,10 +14,7 @@ import { Divider } from '../../Divider'; /** * @see `Tabs` */ -export const TabScrollButton = forwardRef(function TabScrollButton( - inProps: TabScrollButtonProps, - ref -) { +export const TabScrollButton = ({ ref, ...inProps }: TabScrollButtonProps & RefAttributes) => { const { className, direction, @@ -66,4 +63,4 @@ export const TabScrollButton = forwardRef( )} ); -}); +}; diff --git a/packages/react/src/components/Tabs/Tabs.tsx b/packages/react/src/components/Tabs/Tabs.tsx index 8ff7768cc..66f36ad49 100644 --- a/packages/react/src/components/Tabs/Tabs.tsx +++ b/packages/react/src/components/Tabs/Tabs.tsx @@ -4,11 +4,11 @@ import { Children, cloneElement, CSSProperties, - forwardRef, isValidElement, JSX, KeyboardEvent, ReactElement, + RefAttributes, useCallback, useEffect, useImperativeHandle, @@ -151,7 +151,7 @@ let warnedOnceTabPresent = false; /** * Tabs organize content across different screens and views, and let the user navigate between them. */ -export const Tabs = forwardRef(function Tabs(inProps: TabsProps, ref) { +export const Tabs = ({ ref, ...inProps }: TabsProps & RefAttributes) => { const { 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, @@ -738,4 +738,4 @@ export const Tabs = forwardRef(function Tabs(inProps: {conditionalElements.scrollButtonEnd} ); -}); +}; diff --git a/packages/react/src/components/Tag/Tag.tsx b/packages/react/src/components/Tag/Tag.tsx index a38ebc657..727191a25 100644 --- a/packages/react/src/components/Tag/Tag.tsx +++ b/packages/react/src/components/Tag/Tag.tsx @@ -1,5 +1,7 @@ 'use client'; +import { RefAttributes } from 'react'; + import { TagProps } from './Tag.types'; import clsx from 'clsx'; @@ -10,7 +12,7 @@ import { ButtonBase } from '../ButtonBase'; /** * The Tag component is used to categorize content. */ -export const Tag = (inProps: TagProps) => { +export const Tag = ({ ref, ...inProps }: TagProps & RefAttributes) => { const { children, className, @@ -30,6 +32,7 @@ export const Tag = (inProps: TagProps) => { return ( (function TextField(inProps: TextFieldProps, ref) { +export const TextField = ({ ref, ...inProps }: TextFieldProps & RefAttributes) => { const { className, style, @@ -67,4 +67,4 @@ export const TextField = forwardRef(function Tex {!!helperText && {helperText}} ); -}); +}; diff --git a/packages/react/src/components/TextFieldGroup/TextFieldGroup.tsx b/packages/react/src/components/TextFieldGroup/TextFieldGroup.tsx index 1a6c9b615..e4b9ba33f 100644 --- a/packages/react/src/components/TextFieldGroup/TextFieldGroup.tsx +++ b/packages/react/src/components/TextFieldGroup/TextFieldGroup.tsx @@ -1,5 +1,7 @@ 'use client'; +import { RefAttributes } from 'react'; + import { TextFieldGroupProps } from './TextFieldGroup.types'; import clsx from 'clsx'; @@ -9,7 +11,7 @@ import { useDefaultProps } from '../../theming'; /** * This component allows to group multiple text fields for related information. */ -export const TextFieldGroup = (inProps: TextFieldGroupProps) => { +export const TextFieldGroup = ({ ref, ...inProps }: TextFieldGroupProps & RefAttributes) => { const { children, className, @@ -22,6 +24,7 @@ export const TextFieldGroup = (inProps: TextFieldGroupProps) => { return (
diff --git a/packages/react/src/components/Tooltip/Tooltip.tsx b/packages/react/src/components/Tooltip/Tooltip.tsx index 440bbeb89..f3b981e38 100644 --- a/packages/react/src/components/Tooltip/Tooltip.tsx +++ b/packages/react/src/components/Tooltip/Tooltip.tsx @@ -3,9 +3,9 @@ import { cloneElement, FocusEvent, - forwardRef, isValidElement, MouseEvent, + RefAttributes, SyntheticEvent, TouchEvent, useEffect, @@ -71,7 +71,7 @@ const defaultArrowIconMapping = { /** * Tooltips display informative text when the user hovers over, focuses on, or taps an element. */ -export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { +export const Tooltip = ({ ref, ...inProps }: TooltipProps & RefAttributes) => { const { arrow = true, arrowSize = '6', @@ -121,9 +121,10 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { const [openState, setOpenState] = useControlled(false, openProp); - let open = openState; + // There is no point in displaying an empty tooltip. + const open = openState && (!!title || title === 0); - const { current: isControlled } = useRef(openProp !== undefined); + const [isControlled] = useState(openProp !== undefined); useEffect(() => { if (process.env.NODE_ENV === 'production') { @@ -168,7 +169,7 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { }; }, [stopTouchInteraction]); - const handleOpen = (event: MouseEvent | FocusEvent | TouchEvent) => { + const handleOpen = useEvent((event: MouseEvent | FocusEvent | TouchEvent) => { hystersisTimer.clear(); setHystersisOpen(true); @@ -180,7 +181,7 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { if (onOpen && !open) { onOpen(event); } - }; + }); const handleClose = useEvent((event: MouseEvent | FocusEvent | TouchEvent | KeyboardEvent) => { hystersisTimer.start(800 + leaveDelay, () => { @@ -198,7 +199,7 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { }); }); - const handleMouseOver = (event: MouseEvent | FocusEvent | TouchEvent) => { + const handleMouseOver = useEvent((event: MouseEvent | FocusEvent | TouchEvent) => { if (ignoreNonTouchEvents.current && event.type !== 'touchstart') { return; } @@ -220,15 +221,15 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { } else { handleOpen(event); } - }; + }); - const handleMouseLeave = (event: MouseEvent | FocusEvent) => { + const handleMouseLeave = useEvent((event: MouseEvent | FocusEvent) => { enterTimer.clear(); leaveTimer.start(leaveDelay, () => { handleClose(event); }); - }; + }); const { isFocusVisibleRef, @@ -240,16 +241,16 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { // We just need to re-render the Tooltip if the focus-visible state changes. const [, setChildIsFocusVisible] = useState(false); - const handleBlur = (event: FocusEvent) => { + const handleBlur = useEvent((event: FocusEvent) => { handleBlurVisible(event); if (isFocusVisibleRef.current === false) { setChildIsFocusVisible(false); handleMouseLeave(event); } - }; + }); - const handleFocus = (event: FocusEvent) => { + const handleFocus = useEvent((event: FocusEvent) => { // Workaround for https://github.com/facebook/react/issues/7769 // The autoFocus of React might trigger the event before the componentDidMount. // We need to account for this eventuality. @@ -263,9 +264,9 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { setChildIsFocusVisible(true); handleMouseOver(event); } - }; + }); - const detectTouchStart = (event: TouchEvent) => { + const detectTouchStart = useEvent((event: TouchEvent) => { ignoreNonTouchEvents.current = true; const childrenProps = children.props; @@ -273,9 +274,9 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { if (childrenProps.onTouchStart) { childrenProps.onTouchStart(event); } - }; + }); - const handleTouchStart = (event: TouchEvent) => { + const handleTouchStart = useEvent((event: TouchEvent) => { detectTouchStart(event); leaveTimer.clear(); closeTimer.clear(); @@ -289,9 +290,9 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { setBodyUserSelect(prevUserSelect.current); handleMouseOver(event); }); - }; + }); - const handleTouchEnd = (event: TouchEvent) => { + const handleTouchEnd = useEvent((event: TouchEvent) => { if (children.props.onTouchEnd) { children.props.onTouchEnd(event); } @@ -301,7 +302,7 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { leaveTimer.start(leaveTouchDelay, () => { handleClose(event); }); - }; + }); useEffect(() => { if (!open) { @@ -327,14 +328,9 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { const handleRef = useForkRef(getReactElementRef(children), focusVisibleRef, setChildNode, ref); - // There is no point in displaying an empty tooltip. - if (!title && title !== 0) { - open = false; - } - const popperRef = useRef(null); - const handleMouseMove = (event: MouseEvent) => { + const handleMouseMove = useEvent((event: MouseEvent) => { const childrenProps = children.props; if (childrenProps.onMouseMove) { @@ -346,7 +342,7 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { if (popperRef.current) { popperRef.current.update(); } - }; + }); const nameOrDescProps: { title?: string | null; @@ -441,6 +437,7 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { const middleware = useMemo(() => { const items: Middleware[] = [ + // eslint-disable-next-line react-hooks/refs -- the refs are read when the middleware runs, never during render offset(({ placement: currentPlacement, rects }) => { const padding = 8; const arrowOffsetX = 14; @@ -535,6 +532,8 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { className: clsx( 'es-tooltip__tooltip', arrow && 'es-tooltip__tooltip--arrow', + // The flag is read during render on purpose: a change of it must not re-render the tooltip on its own. + // eslint-disable-next-line react-hooks/refs ignoreNonTouchEvents.current && 'es-tooltip__tooltip--touch', placement && `es-tooltip__tooltip--placement--${placement}`, color && `es-tooltip__tooltip--color--${color}`, @@ -607,4 +606,4 @@ export const Tooltip = forwardRef(function Tooltip(inProps: TooltipProps, ref) { ); -}); +}; diff --git a/packages/react/src/components/TooltipEllipsis/TooltipEllipsis.types.ts b/packages/react/src/components/TooltipEllipsis/TooltipEllipsis.types.ts index a28240460..24ec15113 100644 --- a/packages/react/src/components/TooltipEllipsis/TooltipEllipsis.types.ts +++ b/packages/react/src/components/TooltipEllipsis/TooltipEllipsis.types.ts @@ -1,10 +1,7 @@ -import { MutableRefObject, ReactElement } from 'react'; +import { ReactElement, RefObject } from 'react'; import { TooltipProps } from '../Tooltip'; export type TooltipEllipsisProps = Omit & { - children: (props: { - ref: MutableRefObject; - childrenRef: MutableRefObject; - }) => ReactElement; + children: (props: { ref: RefObject; childrenRef: RefObject }) => ReactElement; }; diff --git a/packages/react/src/components/TouchRipple/TouchRipple.tsx b/packages/react/src/components/TouchRipple/TouchRipple.tsx index 719db49e0..cc4246296 100644 --- a/packages/react/src/components/TouchRipple/TouchRipple.tsx +++ b/packages/react/src/components/TouchRipple/TouchRipple.tsx @@ -1,6 +1,6 @@ 'use client'; -import { forwardRef } from 'react'; +import { RefAttributes } from 'react'; import { TouchRippleProps } from './TouchRipple.types'; @@ -11,11 +11,11 @@ import { useDefaultProps } from '../../theming'; /** * The touch ripple for ButtonBase component. */ -export const TouchRipple = forwardRef(function TouchRipple(inProps, ref) { +export const TouchRipple = ({ ref, ...inProps }: TouchRippleProps & RefAttributes) => { const { className, style } = useDefaultProps({ props: inProps, name: 'ESTouchRipple', }); return
; -}); +}; diff --git a/packages/react/src/components/Tour/Tour.tsx b/packages/react/src/components/Tour/Tour.tsx index 0d859becb..9274f0c5f 100644 --- a/packages/react/src/components/Tour/Tour.tsx +++ b/packages/react/src/components/Tour/Tour.tsx @@ -1,6 +1,6 @@ 'use client'; -import { CSSProperties, forwardRef, useEffect, useMemo, useRef, useState } from 'react'; +import { CSSProperties, RefAttributes, useEffect, useMemo, useRef, useState } from 'react'; import { TourContentProps, TourDirection, TourProps } from './Tour.types'; @@ -47,7 +47,7 @@ const toClientRect = (rect: TourRect) => ({ /** * The Tour walks the user through the interface, highlighting one element at a time and showing a card next to it. */ -export const Tour = forwardRef(function Tour(inProps, ref) { +export const Tour = ({ ref, ...inProps }: TourProps & RefAttributes) => { const { steps, open, @@ -163,6 +163,8 @@ export const Tour = forwardRef(function Tour(inProps, controllerRef.current?.abort(); controllerRef.current = null; pendingRef.current = null; + // The tour has to drop the resolved step as soon as it closes, so the reset cannot wait for an event. + // eslint-disable-next-line react-hooks/set-state-in-effect setActive(null); setLoading(false); return; @@ -352,6 +354,8 @@ export const Tour = forwardRef(function Tour(inProps,
)} {isTargetPresent && + // The anchor reads the spotlight ref when floating-ui measures it, never during render. + // eslint-disable-next-line react-hooks/refs (anchorEl ? ( (function Tour(inProps, ); -}); +}; diff --git a/packages/react/src/components/Zoom/Zoom.tsx b/packages/react/src/components/Zoom/Zoom.tsx index bd2df6317..0d6ba7e53 100644 --- a/packages/react/src/components/Zoom/Zoom.tsx +++ b/packages/react/src/components/Zoom/Zoom.tsx @@ -1,6 +1,6 @@ 'use client'; -import { cloneElement, CSSProperties, forwardRef, useRef } from 'react'; +import { cloneElement, CSSProperties, RefAttributes, useRef } from 'react'; import { Transition, TransitionStatus } from 'react-transition-group'; import { ZoomProps } from './Zoom.types'; @@ -8,7 +8,7 @@ import { ZoomProps } from './Zoom.types'; import { useForkRef } from '../../hooks'; import { useDefaultProps } from '../../theming'; import { createTransition, duration } from '../../transitions'; -import { createTransitionCallbacks } from '../../transitions/transitionCallbacks'; +import { useTransitionCallbacks } from '../../transitions/useTransitionCallbacks'; import { getTransitionProps, reflow } from '../../transitions/utils'; import { getReactElementRef } from '../../utils'; @@ -29,7 +29,7 @@ const styles: Partial> = { /** * The Zoom transition scales a single child element in and out. */ -export const Zoom = forwardRef(function Zoom(inProps, ref) { +export const Zoom = ({ ref, ...inProps }: ZoomProps & RefAttributes) => { const { addEndListener, appear = true, @@ -53,7 +53,7 @@ export const Zoom = forwardRef(function Zoom(inProps, ref) { const nodeRef = useRef(null); const handleRef = useForkRef(nodeRef, getReactElementRef(children), ref); - const callbacks = createTransitionCallbacks(nodeRef); + const callbacks = useTransitionCallbacks(nodeRef); const handleEnter = callbacks.enter((node, isAppearing) => { // So the animation always starts from the start. @@ -117,4 +117,4 @@ export const Zoom = forwardRef(function Zoom(inProps, ref) { }} ); -}); +}; diff --git a/packages/react/src/hooks/useForkRef/useForkRef.ts b/packages/react/src/hooks/useForkRef/useForkRef.ts index 671087f37..121af1dbd 100644 --- a/packages/react/src/hooks/useForkRef/useForkRef.ts +++ b/packages/react/src/hooks/useForkRef/useForkRef.ts @@ -3,7 +3,7 @@ import { Ref, RefCallback, useMemo } from 'react'; const setRef = ( - ref: React.MutableRefObject | ((instance: T | null) => void) | null | undefined, + ref: React.RefObject | ((instance: T | null) => void) | null | undefined, value: T | null ) => { if (typeof ref === 'function') { diff --git a/packages/react/src/hooks/useIsFocusVisible/useIsFocusVisible.ts b/packages/react/src/hooks/useIsFocusVisible/useIsFocusVisible.ts index 0cf096b23..725bd9804 100644 --- a/packages/react/src/hooks/useIsFocusVisible/useIsFocusVisible.ts +++ b/packages/react/src/hooks/useIsFocusVisible/useIsFocusVisible.ts @@ -2,7 +2,7 @@ // Based on https://github.com/WICG/focus-visible/blob/v4.1.5/src/focus-visible.js -import { FocusEvent, MutableRefObject, RefCallback, useCallback, useRef } from 'react'; +import { FocusEvent, RefCallback, RefObject, useCallback, useRef } from 'react'; import { Timeout } from '../../utils'; @@ -106,7 +106,7 @@ const isEventFocusVisible = (event: FocusEvent): boolean => { }; export interface UseIsFocusVisibleResult { - isFocusVisibleRef: MutableRefObject; + isFocusVisibleRef: RefObject; onBlur: (event: FocusEvent) => boolean; onFocus: (event: FocusEvent) => boolean; ref: RefCallback; diff --git a/packages/react/src/hooks/useMenuAim/useMenuAim.ts b/packages/react/src/hooks/useMenuAim/useMenuAim.ts index 7827f17d9..65a03c568 100644 --- a/packages/react/src/hooks/useMenuAim/useMenuAim.ts +++ b/packages/react/src/hooks/useMenuAim/useMenuAim.ts @@ -1,6 +1,6 @@ 'use client'; -import { MutableRefObject, useRef } from 'react'; +import { RefObject, useRef } from 'react'; const MOUSE_LOCS_TRACKED = 3; const DELAY = 300; @@ -14,7 +14,7 @@ const DELAY = 300; * @returns The onMouseMove, onMouseOver and onMouseLeave handlers. */ export const useMenuAim = ( - ref: MutableRefObject, + ref: RefObject, position: string, isActive: boolean, callback: (target: HTMLElement) => void diff --git a/packages/react/src/hooks/useSticky/useSticky.ts b/packages/react/src/hooks/useSticky/useSticky.ts index 45a348404..30f36239d 100644 --- a/packages/react/src/hooks/useSticky/useSticky.ts +++ b/packages/react/src/hooks/useSticky/useSticky.ts @@ -1,6 +1,6 @@ 'use client'; -import { MutableRefObject, useEffect, useLayoutEffect } from 'react'; +import { RefObject, useEffect, useLayoutEffect } from 'react'; import { useLatest } from '../useLatest'; import { useResizeObserver } from '../useResizeObserver'; @@ -18,7 +18,7 @@ const setTransform = (element: HTMLElement, transform: string) => { * @param options.relativeTo The scrolling ancestor for the sticky element. */ export const useSticky = ( - ref: MutableRefObject, + ref: RefObject, options: { top?: number; bottom?: number; relativeTo?: HTMLElement | null } ) => { const update = () => { diff --git a/packages/react/src/transitions/transitionCallbacks.ts b/packages/react/src/transitions/useTransitionCallbacks.ts similarity index 87% rename from packages/react/src/transitions/transitionCallbacks.ts rename to packages/react/src/transitions/useTransitionCallbacks.ts index 843a53bb1..dcb51a866 100644 --- a/packages/react/src/transitions/transitionCallbacks.ts +++ b/packages/react/src/transitions/useTransitionCallbacks.ts @@ -8,7 +8,7 @@ export type ESExitCallback = (node: HTMLElement) => void; * Adapts the public transition callbacks, which receive the animated node, to the signature `react-transition-group` * uses when a `nodeRef` is provided. */ -export const createTransitionCallbacks = (nodeRef: RefObject) => ({ +export const useTransitionCallbacks = (nodeRef: RefObject) => ({ enter: (callback?: ESEnterCallback) => (isAppearing: boolean) => { if (callback && nodeRef.current) { callback(nodeRef.current, isAppearing); diff --git a/packages/react/src/utils/setRef.ts b/packages/react/src/utils/setRef.ts index d759078f7..87acac60d 100644 --- a/packages/react/src/utils/setRef.ts +++ b/packages/react/src/utils/setRef.ts @@ -1,4 +1,4 @@ -import { MutableRefObject } from 'react'; +import { RefObject } from 'react'; /** * Assigns a value to a ref, no matter whether it is a callback or an object ref. Falsy refs are a no-op. @@ -7,7 +7,7 @@ import { MutableRefObject } from 'react'; * changes. */ export const setRef = ( - ref: MutableRefObject | ((instance: T | null) => void) | null | undefined, + ref: RefObject | ((instance: T | null) => void) | null | undefined, value: T | null ): void => { if (typeof ref === 'function') {