From fd4948219b59c41d1a61c2e629ac0a773c1dff54 Mon Sep 17 00:00:00 2001 From: Daniil Suvorov Date: Tue, 22 Aug 2023 17:23:02 +0300 Subject: [PATCH] feat: add RootComponent (#5651) --- .../src/components/Accordion/Accordion.tsx | 6 ++-- .../components/AspectRatio/AspectRatio.tsx | 19 ++++------- packages/vkui/src/components/Badge/Badge.tsx | 12 +++++-- .../vkui/src/components/Banner/Banner.tsx | 16 ++++----- .../components/BaseGallery/BaseGallery.tsx | 11 +++---- .../vkui/src/components/BaseGallery/types.ts | 5 ++- .../components/ButtonGroup/ButtonGroup.tsx | 20 ++++------- .../vkui/src/components/Calendar/Calendar.tsx | 21 ++++-------- .../components/CalendarDays/CalendarDays.tsx | 16 +++++---- .../CalendarHeader/CalendarHeader.test.tsx | 4 +++ .../CalendarHeader/CalendarHeader.tsx | 10 +++--- .../CalendarRange/CalendarRange.tsx | 14 ++++---- packages/vkui/src/components/Card/Card.tsx | 25 ++++---------- .../vkui/src/components/CardGrid/CardGrid.tsx | 21 ++++-------- .../src/components/CardScroll/CardScroll.tsx | 12 +++---- .../Cell/CellDragger/CellDragger.tsx | 3 +- packages/vkui/src/components/Chip/Chip.tsx | 12 +++---- .../vkui/src/components/Counter/Counter.tsx | 3 +- .../CustomSelectDropdown.tsx | 5 ++- .../CustomSelectOption/CustomSelectOption.tsx | 6 ++-- .../src/components/DatePicker/DatePicker.tsx | 11 ++++--- packages/vkui/src/components/Div/Div.tsx | 16 +++------ .../components/DropdownIcon/DropdownIcon.tsx | 3 +- packages/vkui/src/components/Epic/Epic.tsx | 13 ++++---- .../components/FixedLayout/FixedLayout.tsx | 5 ++- .../src/components/FocusTrap/FocusTrap.tsx | 12 +++---- .../components/FocusVisible/FocusVisible.tsx | 8 +++-- .../vkui/src/components/FormItem/FormItem.tsx | 12 +++---- .../FormLayoutGroup/FormLayoutGroup.tsx | 18 +++++----- .../src/components/FormStatus/FormStatus.tsx | 6 ++-- .../vkui/src/components/Gradient/Gradient.tsx | 20 ++++------- packages/vkui/src/components/Group/Group.tsx | 19 ++++------- .../vkui/src/components/Header/Header.tsx | 16 ++++----- .../HorizontalCell/HorizontalCell.tsx | 4 +-- .../HorizontalScroll/HorizontalScroll.tsx | 13 ++++---- .../src/components/ImageBase/ImageBase.tsx | 11 +++---- .../ImageBaseBadge/ImageBaseBadge.tsx | 23 +++++-------- .../vkui/src/components/InfoRow/InfoRow.tsx | 3 +- .../src/components/InputLike/InputLike.tsx | 22 ++++--------- packages/vkui/src/components/List/List.tsx | 12 ++++--- .../components/MiniInfoCell/MiniInfoCell.tsx | 8 +++-- .../src/components/ModalCard/ModalCard.tsx | 11 +++---- .../ModalCardBase/ModalCardBase.tsx | 17 ++++------ .../ModalDismissButton/ModalDismissButton.tsx | 3 +- .../src/components/ModalPage/ModalPage.tsx | 12 +++---- .../src/components/Pagination/Pagination.tsx | 17 ++++++---- packages/vkui/src/components/Panel/Panel.tsx | 25 ++++---------- .../components/PanelHeader/PanelHeader.tsx | 18 +++++----- .../PanelHeaderContent/PanelHeaderContent.tsx | 15 ++++----- .../PanelHeaderContext/PanelHeaderContext.tsx | 3 +- .../components/Placeholder/Placeholder.tsx | 17 ++++------ .../src/components/PopoutRoot/PopoutRoot.tsx | 33 +++++++------------ .../PopoutWrapper/PopoutWrapper.tsx | 14 ++++---- .../vkui/src/components/Popper/Popper.tsx | 19 ++++++----- .../vkui/src/components/Progress/Progress.tsx | 16 ++++----- .../components/PromoBanner/PromoBanner.tsx | 10 +++--- .../PullToRefresh/PullToRefreshSpinner.tsx | 23 ++++++------- .../src/components/RadioGroup/RadioGroup.tsx | 20 ++++------- .../src/components/Removable/Removable.tsx | 21 ++++-------- .../RichCell/RichCellIcon/RichCellIcon.tsx | 17 ++++------ packages/vkui/src/components/Root/Root.tsx | 12 +++---- .../RootComponent/RootComponent.test.tsx | 6 ++++ .../RootComponent/RootComponent.tsx | 23 +++++++++++++ .../components/ScrollArrow/ScrollArrow.tsx | 12 +++---- .../vkui/src/components/Search/Search.tsx | 5 ++- .../SegmentedControl/SegmentedControl.tsx | 16 ++++----- .../SegmentedControlOption.tsx | 5 ++- .../SelectMimicry/SelectMimicry.tsx | 5 ++- .../SelectTypography/SelectTypography.tsx | 6 ++-- .../src/components/Separator/Separator.tsx | 12 ++++--- .../vkui/src/components/Slider/Slider.tsx | 5 ++- .../vkui/src/components/Snackbar/Snackbar.tsx | 12 +++---- .../vkui/src/components/Spacing/Spacing.tsx | 10 +++--- .../vkui/src/components/Spinner/Spinner.tsx | 15 ++++++--- .../vkui/src/components/SplitCol/SplitCol.tsx | 18 +++++----- .../components/SplitLayout/SplitLayout.tsx | 5 ++- .../SubnavigationBar/SubnavigationBar.tsx | 25 +++++++------- .../vkui/src/components/Tabbar/Tabbar.tsx | 17 +++++----- .../src/components/TabbarItem/TabbarItem.tsx | 12 +++---- packages/vkui/src/components/Tabs/Tabs.tsx | 24 ++++---------- .../vkui/src/components/TabsItem/TabsItem.tsx | 3 +- .../components/TooltipBase/TooltipBase.tsx | 9 +++-- .../components/Typography/Typography.test.tsx | 6 ++++ .../src/components/Typography/Typography.tsx | 12 +++---- .../src/components/UsersStack/UsersStack.tsx | 12 +++---- packages/vkui/src/components/View/View.tsx | 3 +- .../vkui/src/components/View/ViewInfinite.tsx | 4 +-- .../VisuallyHidden/VisuallyHidden.tsx | 19 +++-------- packages/vkui/src/testing/utils.tsx | 23 +++++++++++++ packages/vkui/src/types.ts | 2 ++ 90 files changed, 531 insertions(+), 614 deletions(-) create mode 100644 packages/vkui/src/components/RootComponent/RootComponent.test.tsx create mode 100644 packages/vkui/src/components/RootComponent/RootComponent.tsx create mode 100644 packages/vkui/src/components/Typography/Typography.test.tsx diff --git a/packages/vkui/src/components/Accordion/Accordion.tsx b/packages/vkui/src/components/Accordion/Accordion.tsx index 22878f71ff..34ee6cc2ad 100644 --- a/packages/vkui/src/components/Accordion/Accordion.tsx +++ b/packages/vkui/src/components/Accordion/Accordion.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; import { HasRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { AccordionSummary } from './AccordionSummary'; import styles from './Accordion.module.css'; @@ -16,8 +16,8 @@ export type AccordionProps = React.DetailsHTMLAttributes & * @since 5.3.0 * @see https://vkcom.github.io/VKUI/#/Accordion */ -export const Accordion = ({ getRootRef, className, ...restProps }: AccordionProps) => ( -
+export const Accordion = (props: AccordionProps) => ( + ); Accordion.Summary = AccordionSummary; diff --git a/packages/vkui/src/components/AspectRatio/AspectRatio.tsx b/packages/vkui/src/components/AspectRatio/AspectRatio.tsx index 7f2ef22d9a..da8ebc8172 100644 --- a/packages/vkui/src/components/AspectRatio/AspectRatio.tsx +++ b/packages/vkui/src/components/AspectRatio/AspectRatio.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; -import { CSSCustomProperties, HasRootRef } from '../../types'; +import { CSSCustomProperties, HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './AspectRatio.module.css'; -export interface AspectRatioProps - extends React.HTMLAttributes, - HasRootRef { +export interface AspectRatioProps extends HTMLAttributesWithRootRef { className?: string; /** * По умолчанию, вложенный контент будет растягиваться и заполнять весь блок. @@ -29,8 +28,6 @@ export function AspectRatio({ ratio, children, mode = 'stretch', - className, - getRootRef, style: styleProp, ...props }: AspectRatioProps): JSX.Element { @@ -39,17 +36,13 @@ export function AspectRatio({ }; return ( -
- {children} -
+ /> ); } diff --git a/packages/vkui/src/components/Badge/Badge.tsx b/packages/vkui/src/components/Badge/Badge.tsx index 287470a430..f48c604b6e 100644 --- a/packages/vkui/src/components/Badge/Badge.tsx +++ b/packages/vkui/src/components/Badge/Badge.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Badge.module.css'; const stylesMode = { @@ -7,13 +9,17 @@ const stylesMode = { prominent: styles['Badge--mode-prominent'], }; -export interface BadgeProps extends React.HTMLAttributes { +export interface BadgeProps extends HTMLAttributesWithRootRef { mode: 'new' | 'prominent'; } /** * @see https://vkcom.github.io/VKUI/#/Badge */ -export const Badge = ({ mode = 'new', className, ...restProps }: BadgeProps) => ( - +export const Badge = ({ mode = 'new', ...restProps }: BadgeProps) => ( + ); diff --git a/packages/vkui/src/components/Banner/Banner.tsx b/packages/vkui/src/components/Banner/Banner.tsx index fb70f520ba..b2a13d9097 100644 --- a/packages/vkui/src/components/Banner/Banner.tsx +++ b/packages/vkui/src/components/Banner/Banner.tsx @@ -3,8 +3,9 @@ import { Icon24Cancel, Icon24Chevron, Icon24Dismiss, Icon24DismissDark } from '@ import { classNames, hasReactNode } from '@vkontakte/vkjs'; import { usePlatform } from '../../hooks/usePlatform'; import { Platform } from '../../lib/platform'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { IconButton } from '../IconButton/IconButton'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable } from '../Tappable/Tappable'; import { Headline } from '../Typography/Headline/Headline'; import { Subhead } from '../Typography/Subhead/Subhead'; @@ -17,7 +18,7 @@ const stylesSize = { m: styles['Banner--size-m'], }; -export interface BannerProps extends React.HTMLAttributes, HasRootRef { +export interface BannerProps extends HTMLAttributesWithRootRef { /** * Тип баннера. */ @@ -105,8 +106,6 @@ export const Banner = ({ actions, onDismiss, dismissLabel = 'Скрыть', - className, - getRootRef, noPadding, ...restProps }: BannerProps) => { @@ -151,18 +150,17 @@ export const Banner = ({ ); return ( -
{asideMode === 'expand' ? ( )} -
+
); }; diff --git a/packages/vkui/src/components/BaseGallery/BaseGallery.tsx b/packages/vkui/src/components/BaseGallery/BaseGallery.tsx index 66b00a44ba..3a4b9e42ac 100644 --- a/packages/vkui/src/components/BaseGallery/BaseGallery.tsx +++ b/packages/vkui/src/components/BaseGallery/BaseGallery.tsx @@ -5,6 +5,7 @@ import { useExternRef } from '../../hooks/useExternRef'; import { useGlobalEventListener } from '../../hooks/useGlobalEventListener'; import { useDOM } from '../../lib/dom'; import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect'; +import { RootComponent } from '../RootComponent/RootComponent'; import { ScrollArrow } from '../ScrollArrow/ScrollArrow'; import { Touch, TouchEvent } from '../Touch/Touch'; import { calcMax, calcMin } from './helpers'; @@ -50,7 +51,6 @@ export const BaseGallery = ({ align = 'left', showArrows, getRef, - className, arrowSize = 'l', ...restProps }: BaseGalleryProps) => { @@ -311,16 +311,15 @@ export const BaseGallery = ({ const isDraggable = isDraggableProp && !layoutState.current.isFullyVisible; return ( -
)} -
+
); }; diff --git a/packages/vkui/src/components/BaseGallery/types.ts b/packages/vkui/src/components/BaseGallery/types.ts index 677cec6fa7..5d515752d7 100644 --- a/packages/vkui/src/components/BaseGallery/types.ts +++ b/packages/vkui/src/components/BaseGallery/types.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { HasAlign, HasRef, HasRootRef } from '../../types'; +import { HasAlign, HasRef, HTMLAttributesWithRootRef } from '../../types'; import { ScrollArrowProps } from '../ScrollArrow/ScrollArrow'; import { TouchEvent, TouchEventHandler } from '../Touch/Touch'; @@ -26,9 +26,8 @@ export interface LayoutState { } export interface BaseGalleryProps - extends Omit, 'onChange' | 'onDragStart' | 'onDragEnd'>, + extends Omit, 'onChange' | 'onDragStart' | 'onDragEnd'>, HasAlign, - HasRootRef, HasRef { slideWidth?: string | number; slideIndex?: number; diff --git a/packages/vkui/src/components/ButtonGroup/ButtonGroup.tsx b/packages/vkui/src/components/ButtonGroup/ButtonGroup.tsx index ae211792a0..6a74f3724c 100644 --- a/packages/vkui/src/components/ButtonGroup/ButtonGroup.tsx +++ b/packages/vkui/src/components/ButtonGroup/ButtonGroup.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; -import type { AlignType, HasRootRef } from '../../types'; +import type { AlignType, HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './ButtonGroup.module.css'; const stylesMode = { @@ -20,9 +21,7 @@ const stylesAlign = { right: styles['ButtonGroup--align-right'], }; -export interface ButtonGroupProps - extends React.HTMLAttributes, - HasRootRef { +export interface ButtonGroupProps extends HTMLAttributesWithRootRef { /** * Задает расположение элементов внутри группы, вертикальное или горизонтальное. */ @@ -51,15 +50,11 @@ export const ButtonGroup = ({ gap = 'm', stretched = false, align = 'left' /* NOTE: Чтобы блоки по-умолчанию не растягивались на всю ширину контейнера */, - getRootRef, - className, - children, ...restProps }: ButtonGroupProps) => { return ( -
- {children} -
+ /> ); }; diff --git a/packages/vkui/src/components/Calendar/Calendar.tsx b/packages/vkui/src/components/Calendar/Calendar.tsx index e4f56e4273..ce0fb0705e 100644 --- a/packages/vkui/src/components/Calendar/Calendar.tsx +++ b/packages/vkui/src/components/Calendar/Calendar.tsx @@ -5,14 +5,15 @@ import { isFirstDay, isLastDay, navigateDate, setTimeEqual } from '../../lib/cal import { isSameDay, isSameMonth } from '../../lib/date'; import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect'; import { warnOnce } from '../../lib/warnOnce'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { CalendarDays, CalendarDaysProps } from '../CalendarDays/CalendarDays'; import { CalendarHeader, CalendarHeaderProps } from '../CalendarHeader/CalendarHeader'; import { CalendarTime, CalendarTimeProps } from '../CalendarTime/CalendarTime'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Calendar.module.css'; export interface CalendarProps - extends Omit, 'onChange'>, + extends Omit, 'onChange'>, Pick, Pick< CalendarHeaderProps, @@ -27,8 +28,7 @@ export interface CalendarProps | 'prevMonthProps' | 'nextMonthProps' >, - Pick, - HasRootRef { + Pick { value?: Date; disablePast?: boolean; disableFuture?: boolean; @@ -68,7 +68,6 @@ export const Calendar = ({ enableTime = false, doneButtonText, weekStartsOn = 1, - getRootRef, disablePickers, changeHoursAriaLabel, changeMinutesAriaLabel, @@ -88,7 +87,6 @@ export const Calendar = ({ prevMonthProps, nextMonthProps, dayProps, - className, listenDayChangesForUpdate, ...props }: CalendarProps) => { @@ -155,14 +153,9 @@ export const Calendar = ({ ); return ( -
)} - + ); }; diff --git a/packages/vkui/src/components/CalendarDays/CalendarDays.tsx b/packages/vkui/src/components/CalendarDays/CalendarDays.tsx index 5d7204170c..9c4863c13c 100644 --- a/packages/vkui/src/components/CalendarDays/CalendarDays.tsx +++ b/packages/vkui/src/components/CalendarDays/CalendarDays.tsx @@ -1,14 +1,18 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { useExternRef } from '../../hooks/useExternRef'; import { useTodayDate } from '../../hooks/useTodayDate'; import { getDaysNames, getWeeks } from '../../lib/calendar'; import { isSameDay, isSameMonth } from '../../lib/date'; +import { HTMLAttributesWithRootRef } from '../../types'; import { CalendarDay, CalendarDayElementProps } from '../CalendarDay/CalendarDay'; import { useConfigProvider } from '../ConfigProvider/ConfigProviderContext'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Footnote } from '../Typography/Footnote/Footnote'; import styles from './CalendarDays.module.css'; -export interface CalendarDaysProps extends Omit, 'onChange'> { +export interface CalendarDaysProps + extends Omit, 'onChange'> { value?: Date | Array; viewDate: Date; weekStartsOn: 0 | 1 | 2 | 3 | 4 | 5 | 6; @@ -49,12 +53,12 @@ export const CalendarDays = ({ size, showNeighboringMonth = false, dayProps, - className, listenDayChangesForUpdate = false, + getRootRef, ...props }: CalendarDaysProps) => { const { locale } = useConfigProvider(); - const ref = React.useRef(null); + const ref = useExternRef(getRootRef); const now = useTodayDate(listenDayChangesForUpdate); const weeks = React.useMemo(() => getWeeks(viewDate, weekStartsOn), [weekStartsOn, viewDate]); @@ -70,11 +74,11 @@ export const CalendarDays = ({ ref.current?.focus(); }, - [onDayChange], + [onDayChange, ref], ); return ( -
+
))} -
+
); }; diff --git a/packages/vkui/src/components/CalendarHeader/CalendarHeader.test.tsx b/packages/vkui/src/components/CalendarHeader/CalendarHeader.test.tsx index f0dc893145..6e8f51de36 100644 --- a/packages/vkui/src/components/CalendarHeader/CalendarHeader.test.tsx +++ b/packages/vkui/src/components/CalendarHeader/CalendarHeader.test.tsx @@ -1,8 +1,12 @@ import * as React from 'react'; import { render } from '@testing-library/react'; +import { noop } from '@vkontakte/vkjs'; +import { baselineComponent } from '../../testing/utils'; import { CalendarHeader } from './CalendarHeader'; describe('CalendarHeader', () => { + baselineComponent((props) => ); + it('displays prev month button', () => { const viewDate = new Date('1970-01-01'); const onChange = jest.fn(); diff --git a/packages/vkui/src/components/CalendarHeader/CalendarHeader.tsx b/packages/vkui/src/components/CalendarHeader/CalendarHeader.tsx index 4eff095675..fe78924075 100644 --- a/packages/vkui/src/components/CalendarHeader/CalendarHeader.tsx +++ b/packages/vkui/src/components/CalendarHeader/CalendarHeader.tsx @@ -8,9 +8,11 @@ import { classNames } from '@vkontakte/vkjs'; import { SizeType } from '../../lib/adaptivity'; import { getMonths, getYears } from '../../lib/calendar'; import { addMonths, setMonth, setYear, subMonths } from '../../lib/date'; +import { HTMLAttributesWithRootRef } from '../../types'; import { AdaptivityProvider } from '../AdaptivityProvider/AdaptivityProvider'; import { useConfigProvider } from '../ConfigProvider/ConfigProviderContext'; import { CustomSelect } from '../CustomSelect/CustomSelect'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable, TappableElementProps } from '../Tappable/Tappable'; import { Paragraph } from '../Typography/Paragraph/Paragraph'; import styles from './CalendarHeader.module.css'; @@ -18,7 +20,7 @@ import styles from './CalendarHeader.module.css'; type ArrowMonthProps = Omit; export interface CalendarHeaderProps - extends Pick, 'className'> { + extends Omit, 'onChange'> { viewDate: Date; prevMonth?: boolean; nextMonth?: boolean; @@ -50,7 +52,6 @@ export const CalendarHeader = ({ disablePickers = false, onNextMonth, onPrevMonth, - className, prevMonthProps = {}, nextMonthProps = {}, prevMonthAriaLabel = 'Предыдущий месяц', @@ -71,6 +72,7 @@ export const CalendarHeader = ({ height={30} /> ), + ...restProps }: CalendarHeaderProps) => { const { locale } = useConfigProvider(); const onMonthsChange = React.useCallback( @@ -106,7 +108,7 @@ export const CalendarHeader = ({ const { className: nextMonthClassName, ...restNextMonthProps } = nextMonthProps; return ( -
+ {prevMonth && ( )} -
+ ); }; diff --git a/packages/vkui/src/components/CalendarRange/CalendarRange.tsx b/packages/vkui/src/components/CalendarRange/CalendarRange.tsx index 221494d0aa..aaaceae9c8 100644 --- a/packages/vkui/src/components/CalendarRange/CalendarRange.tsx +++ b/packages/vkui/src/components/CalendarRange/CalendarRange.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; import { useCalendar } from '../../hooks/useCalendar'; import { isFirstDay, isLastDay, navigateDate, setTimeEqual } from '../../lib/calendar'; import { @@ -12,13 +11,14 @@ import { isWithinInterval, startOfDay, } from '../../lib/date'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { CalendarDays, CalendarDaysProps } from '../CalendarDays/CalendarDays'; import { CalendarHeader, CalendarHeaderProps } from '../CalendarHeader/CalendarHeader'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './CalendarRange.module.css'; export interface CalendarRangeProps - extends Omit, 'onChange'>, + extends Omit, 'onChange'>, Pick< CalendarHeaderProps, | 'prevMonthAriaLabel' @@ -28,8 +28,7 @@ export interface CalendarRangeProps | 'prevMonthIcon' | 'nextMonthIcon' >, - Pick, - HasRootRef { + Pick { value?: Array; disablePast?: boolean; disableFuture?: boolean; @@ -69,7 +68,6 @@ export const CalendarRange = ({ changeDayAriaLabel = 'Изменить день', prevMonthIcon, nextMonthIcon, - className, listenDayChangesForUpdate, ...props }: CalendarRangeProps) => { @@ -181,7 +179,7 @@ export const CalendarRange = ({ ); return ( -
+
-
+ ); }; diff --git a/packages/vkui/src/components/Card/Card.tsx b/packages/vkui/src/components/Card/Card.tsx index f891654ec0..b21eb395d5 100644 --- a/packages/vkui/src/components/Card/Card.tsx +++ b/packages/vkui/src/components/Card/Card.tsx @@ -1,38 +1,27 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Card.module.css'; -export interface CardProps - extends React.HTMLAttributes, - HasRootRef { +export interface CardProps extends HTMLAttributesWithRootRef { mode?: 'tint' | 'shadow' | 'outline' | 'outline-tint'; } /** * @see https://vkcom.github.io/VKUI/#/Card */ -export const Card = ({ - mode = 'tint', - children, - getRootRef, - className, - ...restProps -}: CardProps) => { +export const Card = ({ mode = 'tint', ...restProps }: CardProps) => { const withBorder = mode === 'outline' || mode === 'outline-tint'; return ( -
- {children} -
+ /> ); }; diff --git a/packages/vkui/src/components/CardGrid/CardGrid.tsx b/packages/vkui/src/components/CardGrid/CardGrid.tsx index 586ff46fe0..43e6e9b64f 100644 --- a/packages/vkui/src/components/CardGrid/CardGrid.tsx +++ b/packages/vkui/src/components/CardGrid/CardGrid.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { useAdaptivity } from '../../hooks/useAdaptivity'; import { SizeType } from '../../lib/adaptivity'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './CardGrid.module.css'; const sizeXClassNames = { @@ -15,7 +17,7 @@ const stylesSize = { l: 'vkuiInternalCardGrid--size-l', }; -export interface CardGridProps extends React.HTMLAttributes { +export interface CardGridProps extends HTMLAttributesWithRootRef { size?: 's' | 'm' | 'l'; /** * Если true, то вокруг компонента присутствуют стандартные отсупы сверху/снизу и слева/справа @@ -26,28 +28,19 @@ export interface CardGridProps extends React.HTMLAttributes { /** * @see https://vkcom.github.io/VKUI/#/CardGrid */ -export const CardGrid = ({ - children, - size = 's', - spaced = false, - className, - ...restProps -}: CardGridProps) => { +export const CardGrid = ({ size = 's', spaced = false, ...restProps }: CardGridProps) => { const { sizeX = 'none' } = useAdaptivity(); return ( -
- {children} -
+ /> ); }; diff --git a/packages/vkui/src/components/CardScroll/CardScroll.tsx b/packages/vkui/src/components/CardScroll/CardScroll.tsx index 49bfa3b3e0..30ebb54c74 100644 --- a/packages/vkui/src/components/CardScroll/CardScroll.tsx +++ b/packages/vkui/src/components/CardScroll/CardScroll.tsx @@ -1,7 +1,9 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { useDOM } from '../../lib/dom'; +import { HTMLAttributesWithRootRef } from '../../types'; import { HorizontalScroll, HorizontalScrollProps } from '../HorizontalScroll/HorizontalScroll'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './CardScroll.module.css'; const stylesSize = { @@ -10,7 +12,7 @@ const stylesSize = { l: 'vkuiInternalCardScroll--size-l', }; -export interface CardScrollProps extends React.HTMLAttributes { +export interface CardScrollProps extends HTMLAttributesWithRootRef { /** * При `size=false` ширина `Card` будет регулироваться контентом внутри. В остальных случаях — будет явно задана в процентах. */ @@ -27,7 +29,6 @@ export const CardScroll = ({ size = 's', showArrows = true, withSpaces = true, - className, ...restProps }: CardScrollProps) => { const refContainer = React.useRef(null); @@ -88,14 +89,13 @@ export const CardScroll = ({ } return ( -
-
+ ); }; diff --git a/packages/vkui/src/components/Cell/CellDragger/CellDragger.tsx b/packages/vkui/src/components/Cell/CellDragger/CellDragger.tsx index 5bcdd677ce..06092090a9 100644 --- a/packages/vkui/src/components/Cell/CellDragger/CellDragger.tsx +++ b/packages/vkui/src/components/Cell/CellDragger/CellDragger.tsx @@ -3,12 +3,13 @@ import { Icon24Reorder, Icon24ReorderIos } from '@vkontakte/icons'; import { classNames } from '@vkontakte/vkjs'; import { usePlatform } from '../../../hooks/usePlatform'; import { Platform } from '../../../lib/platform'; +import { HTMLAttributesWithRootRef } from '../../../types'; import { Touch } from '../../Touch/Touch'; import { DraggableProps } from '../useDraggable'; import styles from './CellDragger.module.css'; type CellDraggerProps = DraggableProps & - Omit, keyof DraggableProps>; + Omit, keyof DraggableProps>; export const CellDragger = ({ onDragStart, diff --git a/packages/vkui/src/components/Chip/Chip.tsx b/packages/vkui/src/components/Chip/Chip.tsx index 879af22e29..4b042c3dfe 100644 --- a/packages/vkui/src/components/Chip/Chip.tsx +++ b/packages/vkui/src/components/Chip/Chip.tsx @@ -4,6 +4,8 @@ import { classNames, hasReactNode, noop } from '@vkontakte/vkjs'; import { useAdaptivity } from '../../hooks/useAdaptivity'; import { SizeType } from '../../lib/adaptivity'; import { getTitleFromChildren } from '../../lib/utils'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable } from '../Tappable/Tappable'; import { Footnote } from '../Typography/Footnote/Footnote'; import styles from './Chip.module.css'; @@ -21,7 +23,7 @@ export interface ChipOption { [otherProp: string]: any; } -export interface ChipProps extends React.HTMLAttributes { +export interface ChipProps extends HTMLAttributesWithRootRef { value: ChipValue; option?: ChipOption; onRemove?: (event?: React.MouseEvent, value?: ChipValue) => void; @@ -49,7 +51,6 @@ export const Chip = ({ before = null, after, children, - className, ...restProps }: ChipProps) => { const { sizeY = 'none' } = useAdaptivity(); @@ -62,12 +63,11 @@ export const Chip = ({ const title = getTitleFromChildren(children); return ( -
)}
- + ); }; diff --git a/packages/vkui/src/components/Counter/Counter.tsx b/packages/vkui/src/components/Counter/Counter.tsx index 316b87721e..44c09e228f 100644 --- a/packages/vkui/src/components/Counter/Counter.tsx +++ b/packages/vkui/src/components/Counter/Counter.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Caption } from '../Typography/Caption/Caption'; import { Headline } from '../Typography/Headline/Headline'; import styles from './Counter.module.css'; @@ -17,7 +18,7 @@ const sizeClassNames = { m: styles['Counter--size-m'], }; -export interface CounterProps extends React.HTMLAttributes { +export interface CounterProps extends HTMLAttributesWithRootRef { /** * Тип счетчика. В режиме `inherit` если компонент находится в кнопке, то * цвета зависят от кнопки. Если компонент находится вне кнопки, применяется diff --git a/packages/vkui/src/components/CustomSelectDropdown/CustomSelectDropdown.tsx b/packages/vkui/src/components/CustomSelectDropdown/CustomSelectDropdown.tsx index 1dc608aafe..979d80a964 100644 --- a/packages/vkui/src/components/CustomSelectDropdown/CustomSelectDropdown.tsx +++ b/packages/vkui/src/components/CustomSelectDropdown/CustomSelectDropdown.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import type { Placement } from '../../lib/floating'; -import { HasRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { CustomScrollView } from '../CustomScrollView/CustomScrollView'; import { TrackerOptionsProps } from '../CustomScrollView/useTrackerVisibility'; import { Popper } from '../Popper/Popper'; @@ -9,8 +9,7 @@ import { Spinner } from '../Spinner/Spinner'; import styles from './CustomSelectDropdown.module.css'; export interface CustomSelectDropdownProps - extends React.HTMLAttributes, - HasRef, + extends HTMLAttributesWithRootRef, TrackerOptionsProps { targetRef: React.RefObject; placement?: Placement; diff --git a/packages/vkui/src/components/CustomSelectOption/CustomSelectOption.tsx b/packages/vkui/src/components/CustomSelectOption/CustomSelectOption.tsx index 6626add98a..e921a710a0 100644 --- a/packages/vkui/src/components/CustomSelectOption/CustomSelectOption.tsx +++ b/packages/vkui/src/components/CustomSelectOption/CustomSelectOption.tsx @@ -4,7 +4,7 @@ import { classNames, hasReactNode } from '@vkontakte/vkjs'; import { useAdaptivity } from '../../hooks/useAdaptivity'; import { SizeType } from '../../lib/adaptivity'; import { warnOnce } from '../../lib/warnOnce'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Footnote } from '../Typography/Footnote/Footnote'; import { Paragraph } from '../Typography/Paragraph/Paragraph'; import styles from './CustomSelectOption.module.css'; @@ -14,9 +14,7 @@ const sizeYClassNames = { [SizeType.REGULAR]: styles['CustomSelectOption--sizeY-regular'], }; -export interface CustomSelectOptionProps - extends React.HTMLAttributes, - HasRootRef { +export interface CustomSelectOptionProps extends HTMLAttributesWithRootRef { /** * Вставляет основной контент. * @deprecated since v6.0.0 diff --git a/packages/vkui/src/components/DatePicker/DatePicker.tsx b/packages/vkui/src/components/DatePicker/DatePicker.tsx index 113b7d8748..8bfdf5f785 100644 --- a/packages/vkui/src/components/DatePicker/DatePicker.tsx +++ b/packages/vkui/src/components/DatePicker/DatePicker.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; -import { classNames, leadingZero } from '@vkontakte/vkjs'; +import { leadingZero } from '@vkontakte/vkjs'; import { range } from '../../helpers/range'; import { useAdaptivityHasPointer } from '../../hooks/useAdaptivityHasPointer'; +import { HTMLAttributesWithRootRef } from '../../types'; import { CustomSelect } from '../CustomSelect/CustomSelect'; import { Input } from '../Input/Input'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './DatePicker.module.css'; const DefaultMonths: string[] = [ @@ -28,7 +30,7 @@ export type DatePickerDateFormat = { }; export interface DatePickerProps - extends Omit, 'defaultValue' | 'min' | 'max'> { + extends Omit, 'defaultValue' | 'min' | 'max'> { min?: DatePickerDateFormat; max?: DatePickerDateFormat; name?: string; @@ -77,7 +79,6 @@ const DatePickerCustom = ({ year = 0, onDateChange, disabled, - className, ...restProps }: DatePickerProps & Partial) => { const onSelectChange: React.ChangeEventHandler = (e) => { @@ -101,7 +102,7 @@ const DatePickerCustom = ({ value: value, })); return ( -
+
-
+
); }; diff --git a/packages/vkui/src/components/Div/Div.tsx b/packages/vkui/src/components/Div/Div.tsx index cd3c8cb1fb..8d86378b55 100644 --- a/packages/vkui/src/components/Div/Div.tsx +++ b/packages/vkui/src/components/Div/Div.tsx @@ -1,19 +1,11 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Div.module.css'; -export interface DivProps - extends React.HTMLAttributes, - HasRootRef {} +export type DivProps = HTMLAttributesWithRootRef; /** * @see https://vkcom.github.io/VKUI/#/Div */ -export const Div = ({ children, getRootRef, className, ...restProps }: DivProps) => { - return ( -
- {children} -
- ); -}; +export const Div = (props: DivProps) => ; diff --git a/packages/vkui/src/components/DropdownIcon/DropdownIcon.tsx b/packages/vkui/src/components/DropdownIcon/DropdownIcon.tsx index bac1749794..ef32b7b62a 100644 --- a/packages/vkui/src/components/DropdownIcon/DropdownIcon.tsx +++ b/packages/vkui/src/components/DropdownIcon/DropdownIcon.tsx @@ -7,8 +7,9 @@ import { } from '@vkontakte/icons'; import { classNames } from '@vkontakte/vkjs'; import { useAdaptivityConditionalRender } from '../../hooks/useAdaptivityConditionalRender'; +import { HTMLAttributesWithRootRef } from '../../types'; -export interface DropdownIconProps extends React.HTMLAttributes { +export interface DropdownIconProps extends HTMLAttributesWithRootRef { opened?: boolean; } diff --git a/packages/vkui/src/components/Epic/Epic.tsx b/packages/vkui/src/components/Epic/Epic.tsx index 6bc3663f4f..3b2c171d09 100644 --- a/packages/vkui/src/components/Epic/Epic.tsx +++ b/packages/vkui/src/components/Epic/Epic.tsx @@ -2,10 +2,12 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { getNavId } from '../../lib/getNavId'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { ScrollSaver } from './ScrollSaver'; import styles from './Epic.module.css'; -export interface EpicProps extends React.HTMLAttributes { +export interface EpicProps extends HTMLAttributesWithRootRef { tabbar?: React.ReactNode; activeStory: string; children: React.ReactElement | Iterable; @@ -16,9 +18,8 @@ const warn = warnOnce('Epic'); /** * @see https://vkcom.github.io/VKUI/#/Epic */ -export const Epic = (props: EpicProps) => { +export const Epic = ({ activeStory, tabbar, children, ...restProps }: EpicProps) => { const scroll = React.useRef<{ [key: string]: number }>({}).current; - const { activeStory, tabbar, children, className, ...restProps } = props; const story = (React.Children.toArray(children).find( @@ -26,9 +27,9 @@ export const Epic = (props: EpicProps) => { ) as React.ReactElement | undefined) ?? null; return ( -
{ {story} {tabbar} -
+
); }; diff --git a/packages/vkui/src/components/FixedLayout/FixedLayout.tsx b/packages/vkui/src/components/FixedLayout/FixedLayout.tsx index 4f6d200f1f..684897c2ee 100644 --- a/packages/vkui/src/components/FixedLayout/FixedLayout.tsx +++ b/packages/vkui/src/components/FixedLayout/FixedLayout.tsx @@ -5,7 +5,7 @@ import { useGlobalEventListener } from '../../hooks/useGlobalEventListener'; import { usePlatform } from '../../hooks/usePlatform'; import { useDOM } from '../../lib/dom'; import { Platform } from '../../lib/platform'; -import { HasRef, HasRootRef } from '../../types'; +import { HasRef, HTMLAttributesWithRootRef } from '../../types'; import { SplitColContext } from '../SplitCol/SplitColContext'; import { TooltipContainer } from '../Tooltip/TooltipContainer'; import styles from './FixedLayout.module.css'; @@ -19,8 +19,7 @@ const stylesVertical = { }; export interface FixedLayoutProps - extends React.HTMLAttributes, - HasRootRef, + extends HTMLAttributesWithRootRef, HasRef { vertical?: 'top' | 'bottom'; /** diff --git a/packages/vkui/src/components/FocusTrap/FocusTrap.tsx b/packages/vkui/src/components/FocusTrap/FocusTrap.tsx index 002d459751..56a9751ef4 100644 --- a/packages/vkui/src/components/FocusTrap/FocusTrap.tsx +++ b/packages/vkui/src/components/FocusTrap/FocusTrap.tsx @@ -9,9 +9,9 @@ import { HasComponent, HasRootRef } from '../../types'; import { AppRootContext } from '../AppRoot/AppRootContext'; const FOCUSABLE_ELEMENTS: string = FOCUSABLE_ELEMENTS_LIST.join(); -export interface FocusTrapProps - extends React.AllHTMLAttributes, - HasRootRef, +export interface FocusTrapProps + extends React.AllHTMLAttributes, + HasRootRef, HasComponent { restoreFocus?: boolean; timeout?: number; @@ -21,7 +21,7 @@ export interface FocusTrapProps /** * @see https://vkcom.github.io/VKUI/#/FocusTrap */ -export const FocusTrap = ({ +export const FocusTrap = ({ Component = 'div', onClose, restoreFocus = true, @@ -29,8 +29,8 @@ export const FocusTrap = ({ getRootRef, children, ...restProps -}: FocusTrapProps) => { - const ref = useExternRef(getRootRef); +}: FocusTrapProps) => { + const ref = useExternRef(getRootRef); const { document, window } = useDOM(); diff --git a/packages/vkui/src/components/FocusVisible/FocusVisible.tsx b/packages/vkui/src/components/FocusVisible/FocusVisible.tsx index 8d92ae0d19..5d74cab195 100644 --- a/packages/vkui/src/components/FocusVisible/FocusVisible.tsx +++ b/packages/vkui/src/components/FocusVisible/FocusVisible.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HasRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './FocusVisible.module.css'; const stylesMode = { @@ -10,7 +12,7 @@ const stylesMode = { export type FocusVisibleMode = 'inside' | 'outside' | 'outline'; -export interface FocusVisibleProps { +export interface FocusVisibleProps extends HasRootRef { visible: boolean | undefined; mode: FocusVisibleMode; thin?: boolean; @@ -20,10 +22,10 @@ export interface FocusVisibleProps { * @see https://vkcom.github.io/VKUI/#/FocusVisible */ export const FocusVisible = ({ visible, mode, thin, ...restProps }: FocusVisibleProps) => ( - {removable ? ( @@ -131,6 +129,6 @@ export const FormItem = ({ ) : ( wrappedChildren )} - + ); }; diff --git a/packages/vkui/src/components/FormLayoutGroup/FormLayoutGroup.tsx b/packages/vkui/src/components/FormLayoutGroup/FormLayoutGroup.tsx index 3f9850d9ad..9536c46149 100644 --- a/packages/vkui/src/components/FormLayoutGroup/FormLayoutGroup.tsx +++ b/packages/vkui/src/components/FormLayoutGroup/FormLayoutGroup.tsx @@ -3,8 +3,9 @@ import { classNames, noop } from '@vkontakte/vkjs'; import { useAdaptivity } from '../../hooks/useAdaptivity'; import { useExternRef } from '../../hooks/useExternRef'; import { SizeType } from '../../lib/adaptivity'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Removable, RemovableProps } from '../Removable/Removable'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './FormLayoutGroup.module.css'; const sizeYClassNames = { @@ -19,9 +20,8 @@ const sizeYClassNames = { }; export interface FormLayoutGroupProps - extends React.HTMLAttributes, - RemovableProps, - HasRootRef { + extends HTMLAttributesWithRootRef, + RemovableProps { mode?: 'vertical' | 'horizontal'; /** * Только для режима horizontal. Дает возможность удалить всю группу `FormItem`. @@ -47,7 +47,6 @@ export const FormLayoutGroup = ({ removePlaceholder = 'Удалить', onRemove = noop, getRootRef, - className, ...restProps }: FormLayoutGroupProps) => { const { sizeY = 'none' } = useAdaptivity(); @@ -56,9 +55,9 @@ export const FormLayoutGroup = ({ const rootEl = useExternRef(getRootRef); return ( -
@@ -99,6 +97,6 @@ export const FormLayoutGroup = ({ )} -
+ ); }; diff --git a/packages/vkui/src/components/FormStatus/FormStatus.tsx b/packages/vkui/src/components/FormStatus/FormStatus.tsx index d4cdaab3d0..df110a84b4 100644 --- a/packages/vkui/src/components/FormStatus/FormStatus.tsx +++ b/packages/vkui/src/components/FormStatus/FormStatus.tsx @@ -1,12 +1,10 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Banner } from '../Banner/Banner'; import styles from './FormStatus.module.css'; -export interface FormStatusProps - extends React.HTMLAttributes, - HasRootRef { +export interface FormStatusProps extends HTMLAttributesWithRootRef { mode?: 'default' | 'error'; header?: React.ReactNode; } diff --git a/packages/vkui/src/components/Gradient/Gradient.tsx b/packages/vkui/src/components/Gradient/Gradient.tsx index 8c0386f682..8779b92f28 100644 --- a/packages/vkui/src/components/Gradient/Gradient.tsx +++ b/packages/vkui/src/components/Gradient/Gradient.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Gradient.module.css'; const stylesMode = { @@ -13,7 +15,7 @@ const stylesTo = { bottom: styles['Gradient--to-bottom'], }; -export interface GradientProps extends React.HTMLAttributes { +export interface GradientProps extends HTMLAttributesWithRootRef { /** * Тип градиента */ @@ -27,20 +29,12 @@ export interface GradientProps extends React.HTMLAttributes { /** * @see https://vkcom.github.io/VKUI/#/Gradient */ -export const Gradient = ({ - mode = 'tint', - children, - to = 'top', - className, - ...restProps -}: GradientProps) => { +export const Gradient = ({ mode = 'tint', to = 'top', ...restProps }: GradientProps) => { return ( -
- {children} -
+ baseClassName={classNames(stylesMode[mode], stylesTo[to])} + /> ); }; diff --git a/packages/vkui/src/components/Group/Group.tsx b/packages/vkui/src/components/Group/Group.tsx index 8a1c7a729a..2a34a07719 100644 --- a/packages/vkui/src/components/Group/Group.tsx +++ b/packages/vkui/src/components/Group/Group.tsx @@ -5,8 +5,9 @@ import { usePlatform } from '../../hooks/usePlatform'; import { SizeType } from '../../lib/adaptivity'; import { Platform } from '../../lib/platform'; import { warnOnce } from '../../lib/warnOnce'; -import { HasChildren, HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { ModalRootContext } from '../ModalRoot/ModalRootContext'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Separator } from '../Separator/Separator'; import { Spacing } from '../Spacing/Spacing'; import { Footnote } from '../Typography/Footnote/Footnote'; @@ -28,10 +29,7 @@ const stylesPadding = { m: styles['Group--padding-m'], }; -export interface GroupProps - extends HasRootRef, - React.HTMLAttributes, - HasChildren { +export interface GroupProps extends HTMLAttributesWithRootRef { header?: React.ReactNode; description?: React.ReactNode; /** @@ -62,10 +60,8 @@ export const Group = ({ description, children, separator = 'auto', - getRootRef, mode: modeProps, padding = 'm', - className, tabIndex: tabIndexProp, ...restProps }: GroupProps) => { @@ -100,11 +96,11 @@ export const Group = ({ return ( <> -
{header} @@ -120,7 +115,7 @@ export const Group = ({ {hasReactNode(description) && ( {description} )} -
+ {separator !== 'hide' && ( diff --git a/packages/vkui/src/components/Header/Header.tsx b/packages/vkui/src/components/Header/Header.tsx index 20f2fba6f2..33baeb5c4f 100644 --- a/packages/vkui/src/components/Header/Header.tsx +++ b/packages/vkui/src/components/Header/Header.tsx @@ -2,7 +2,8 @@ import * as React from 'react'; import { classNames, hasReactNode, isPrimitiveReactNode } from '@vkontakte/vkjs'; import { usePlatform } from '../../hooks/usePlatform'; import { Platform } from '../../lib/platform'; -import { HasComponent, HasRootRef } from '../../types'; +import { HasComponent, HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Footnote } from '../Typography/Footnote/Footnote'; import { Headline } from '../Typography/Headline/Headline'; import { Paragraph } from '../Typography/Paragraph/Paragraph'; @@ -10,7 +11,7 @@ import { Subhead } from '../Typography/Subhead/Subhead'; import { Title } from '../Typography/Title/Title'; import styles from './Header.module.css'; -export interface HeaderProps extends React.HTMLAttributes, HasRootRef { +export interface HeaderProps extends HTMLAttributesWithRootRef { mode?: 'primary' | 'secondary' | 'tertiary'; size?: 'regular' | 'large'; subtitle?: React.ReactNode; @@ -78,24 +79,21 @@ export const Header = ({ subtitle, indicator, aside, - getRootRef, multiline, - className, ...restProps }: HeaderProps) => { const platform = usePlatform(); return ( -
@@ -138,6 +136,6 @@ export const Header = ({ {aside} )} -
+ ); }; diff --git a/packages/vkui/src/components/HorizontalCell/HorizontalCell.tsx b/packages/vkui/src/components/HorizontalCell/HorizontalCell.tsx index 9d198dad97..5bcafcf420 100644 --- a/packages/vkui/src/components/HorizontalCell/HorizontalCell.tsx +++ b/packages/vkui/src/components/HorizontalCell/HorizontalCell.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; -import { HasComponent, HasRef, HasRootRef } from '../../types'; +import { HasComponent, HasRef, HasRootRef, HTMLAttributesWithRootRef } from '../../types'; import { Avatar } from '../Avatar/Avatar'; import { Tappable } from '../Tappable/Tappable'; import { Caption } from '../Typography/Caption/Caption'; @@ -14,7 +14,7 @@ const stylesSize = { l: styles['HorizontalCell--size-l'], }; -interface CellTypographyProps extends React.HTMLAttributes { +interface CellTypographyProps extends HTMLAttributesWithRootRef { size: HorizontalCellProps['size']; } diff --git a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx index a31227f194..fece771cda 100644 --- a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx +++ b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx @@ -4,7 +4,8 @@ import { useAdaptivityHasPointer } from '../../hooks/useAdaptivityHasPointer'; import { useEventListener } from '../../hooks/useEventListener'; import { useExternRef } from '../../hooks/useExternRef'; import { easeInOutSine } from '../../lib/fx'; -import { HasRef } from '../../types'; +import { HasRef, HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { ScrollArrow } from '../ScrollArrow/ScrollArrow'; import styles from './HorizontalScroll.module.css'; @@ -26,7 +27,7 @@ interface ScrollContext { export type ScrollPositionHandler = (currentPosition: number) => number; export interface HorizontalScrollProps - extends React.HTMLAttributes, + extends HTMLAttributesWithRootRef, HasRef { /** * Функция для расчета величины прокрутки при клике на левую стрелку. @@ -140,7 +141,6 @@ export const HorizontalScroll = ({ arrowOffsetY, scrollAnimationDuration = SCROLL_ONE_FRAME_TIME, getRef, - className, scrollOnAnyWheel = false, ...restProps }: HorizontalScrollProps) => { @@ -243,13 +243,12 @@ export const HorizontalScroll = ({ ); return ( -
@@ -280,6 +279,6 @@ export const HorizontalScroll = ({
{children}
-
+ ); }; diff --git a/packages/vkui/src/components/ImageBase/ImageBase.tsx b/packages/vkui/src/components/ImageBase/ImageBase.tsx index 4f618b42e6..2e1af37d6e 100644 --- a/packages/vkui/src/components/ImageBase/ImageBase.tsx +++ b/packages/vkui/src/components/ImageBase/ImageBase.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { useExternRef } from '../../hooks/useExternRef'; import type { HasRef, HasRootRef, LiteralUnion } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { ImageBaseBadge, type ImageBaseBadgeProps } from './ImageBaseBadge/ImageBaseBadge'; import { ImageBaseOverlay, type ImageBaseOverlayProps } from './ImageBaseOverlay/ImageBaseOverlay'; import { ImageBaseContext } from './context'; @@ -75,8 +76,6 @@ export const ImageBase = ({ width, height, style, - className, - getRootRef, withBorder = true, 'fallbackIcon': fallbackIconProp, children, @@ -153,12 +152,10 @@ export const ImageBase = ({ return ( -
{fallbackIcon}
} {children} {withBorder &&
} -
+
); }; diff --git a/packages/vkui/src/components/ImageBase/ImageBaseBadge/ImageBaseBadge.tsx b/packages/vkui/src/components/ImageBase/ImageBaseBadge/ImageBaseBadge.tsx index 768bd97a3a..047325b213 100644 --- a/packages/vkui/src/components/ImageBase/ImageBaseBadge/ImageBaseBadge.tsx +++ b/packages/vkui/src/components/ImageBase/ImageBaseBadge/ImageBaseBadge.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HasRootRef } from '../../../types'; +import { RootComponent } from '../../RootComponent/RootComponent'; import { ImageBaseContext } from '../context'; import type { ImageBaseExpectedIconProps } from '../types'; import { validateBadgeIcon } from '../validators'; @@ -10,7 +12,7 @@ const backgroundStyles = { shadow: styles['ImageBaseBadge--background-shadow'], }; -export interface ImageBaseBadgeProps extends React.AriaAttributes { +export interface ImageBaseBadgeProps extends React.AriaAttributes, HasRootRef { /** * Вид подложки под иконку. * @@ -38,26 +40,19 @@ export interface ImageBaseBadgeProps extends React.AriaAttributes { * * > Не используйте при `size < 24` */ -export const ImageBaseBadge = ({ - background = 'shadow', - children, - className, - ...restProps -}: ImageBaseBadgeProps) => { +export const ImageBaseBadge = ({ background = 'shadow', ...restProps }: ImageBaseBadgeProps) => { if (process.env.NODE_ENV === 'development') { - if (children) { + if (restProps.children) { // eslint-disable-next-line react-hooks/rules-of-hooks const { size } = React.useContext(ImageBaseContext); - validateBadgeIcon(size, { name: 'children', value: children }); + validateBadgeIcon(size, { name: 'children', value: restProps.children }); } } return ( -
- {children} -
+ baseClassName={classNames(styles['ImageBaseBadge'], backgroundStyles[background])} + /> ); }; diff --git a/packages/vkui/src/components/InfoRow/InfoRow.tsx b/packages/vkui/src/components/InfoRow/InfoRow.tsx index 788504ff10..9d9d93ab54 100644 --- a/packages/vkui/src/components/InfoRow/InfoRow.tsx +++ b/packages/vkui/src/components/InfoRow/InfoRow.tsx @@ -1,11 +1,12 @@ import * as React from 'react'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Headline } from '../Typography/Headline/Headline'; import { Subhead } from '../Typography/Subhead/Subhead'; import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden'; import styles from './InfoRow.module.css'; -export interface InfoRowProps extends React.HTMLAttributes { +export interface InfoRowProps extends HTMLAttributesWithRootRef { header: React.ReactNode; } diff --git a/packages/vkui/src/components/InputLike/InputLike.tsx b/packages/vkui/src/components/InputLike/InputLike.tsx index 8af6b47cd6..80571bcc28 100644 --- a/packages/vkui/src/components/InputLike/InputLike.tsx +++ b/packages/vkui/src/components/InputLike/InputLike.tsx @@ -1,13 +1,11 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; import { callMultiple } from '../../lib/callMultiple'; import { stopPropagation } from '../../lib/utils'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './InputLike.module.css'; -export interface InputLikeProps - extends React.HTMLAttributes, - HasRootRef { +export interface InputLikeProps extends HTMLAttributesWithRootRef { length: number; index: number; value?: string; @@ -35,8 +33,6 @@ export const InputLike = ({ onElementSelect, onClick, onFocus, - getRootRef, - className, ...props }: InputLikeProps) => { const handleElementSelect = React.useCallback( @@ -48,14 +44,10 @@ export const InputLike = ({ ); return ( - )} {getMaskElements(length - (value?.length ?? 0))} - + ); }; diff --git a/packages/vkui/src/components/List/List.tsx b/packages/vkui/src/components/List/List.tsx index 15bc1bda11..b7aeee5db0 100644 --- a/packages/vkui/src/components/List/List.tsx +++ b/packages/vkui/src/components/List/List.tsx @@ -1,25 +1,27 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { ListContext } from './ListContext'; import styles from './List.module.css'; -export type ListProps = React.HTMLAttributes; +export type ListProps = HTMLAttributesWithRootRef; /** * @see https://vkcom.github.io/VKUI/#/List */ -export const List = ({ children, className, ...restProps }: ListProps) => { +export const List = ({ children, ...restProps }: ListProps) => { const [isDragging, toggleDrag] = React.useState(false); return ( -
({ toggleDrag }), [])}> {children} -
+ ); }; diff --git a/packages/vkui/src/components/MiniInfoCell/MiniInfoCell.tsx b/packages/vkui/src/components/MiniInfoCell/MiniInfoCell.tsx index 8c9c9bca14..4edf84853d 100644 --- a/packages/vkui/src/components/MiniInfoCell/MiniInfoCell.tsx +++ b/packages/vkui/src/components/MiniInfoCell/MiniInfoCell.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { Icon16Chevron } from '@vkontakte/icons'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable } from '../Tappable/Tappable'; import { Paragraph } from '../Typography/Paragraph/Paragraph'; import styles from './MiniInfoCell.module.css'; @@ -17,7 +19,7 @@ const stylesTextWrap = { short: styles['MiniInfoCell--textWrap-short'], }; -export interface MiniInfoCellProps extends React.HTMLAttributes { +export interface MiniInfoCellProps extends HTMLAttributesWithRootRef { /** * Иконка слева.
* Рекомендуется использовать иконки размера 20. @@ -96,8 +98,8 @@ export const MiniInfoCell = ({ {cellContent} ) : ( -
+ {cellContent} -
+ ); }; diff --git a/packages/vkui/src/components/ModalCard/ModalCard.tsx b/packages/vkui/src/components/ModalCard/ModalCard.tsx index 79db0b72de..792ee6506b 100644 --- a/packages/vkui/src/components/ModalCard/ModalCard.tsx +++ b/packages/vkui/src/components/ModalCard/ModalCard.tsx @@ -7,6 +7,7 @@ import { warnOnce } from '../../lib/warnOnce'; import { ModalCardBase, ModalCardBaseProps } from '../ModalCardBase/ModalCardBase'; import { ModalRootContext, useModalRegistry } from '../ModalRoot/ModalRootContext'; import { ModalType } from '../ModalRoot/types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './ModalCard.module.css'; const platformClassNames = { @@ -31,9 +32,7 @@ export const ModalCard = ({ onClose, nav, id, - className, size, - getRootRef, ...restProps }: ModalCardProps) => { const { isDesktop } = useAdaptivityWithJSMediaQueries(); @@ -43,17 +42,15 @@ export const ModalCard = ({ const { refs } = useModalRegistry(getNavId({ nav, id }, warn), ModalType.CARD); return ( -
{children} -
+ ); }; diff --git a/packages/vkui/src/components/ModalCardBase/ModalCardBase.tsx b/packages/vkui/src/components/ModalCardBase/ModalCardBase.tsx index 54e1052990..95c8dad9cc 100644 --- a/packages/vkui/src/components/ModalCardBase/ModalCardBase.tsx +++ b/packages/vkui/src/components/ModalCardBase/ModalCardBase.tsx @@ -6,17 +6,16 @@ import { useKeyboard } from '../../hooks/useKeyboard'; import { usePlatform } from '../../hooks/usePlatform'; import { SizeType } from '../../lib/adaptivity'; import { Platform } from '../../lib/platform'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { AdaptivityContext } from '../AdaptivityProvider/AdaptivityContext'; import { ModalDismissButton } from '../ModalDismissButton/ModalDismissButton'; import { PanelHeaderButton } from '../PanelHeaderButton/PanelHeaderButton'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Subhead } from '../Typography/Subhead/Subhead'; import { Title } from '../Typography/Title/Title'; import styles from './ModalCardBase.module.css'; -export interface ModalCardBaseProps - extends React.HTMLAttributes, - HasRootRef { +export interface ModalCardBaseProps extends HTMLAttributesWithRootRef { /** * Иконка. * @@ -64,7 +63,6 @@ export interface ModalCardBaseProps * @see https://vkcom.github.io/VKUI/#/ModalCardBase */ export const ModalCardBase = ({ - getRootRef, icon, header, subheader, @@ -72,7 +70,6 @@ export const ModalCardBase = ({ actions, onClose, dismissLabel = 'Скрыть', - className, style, size: sizeProp, ...restProps @@ -86,15 +83,13 @@ export const ModalCardBase = ({ const size = isDesktop ? sizeProp : undefined; return ( -
)}
-
+ ); }; diff --git a/packages/vkui/src/components/ModalDismissButton/ModalDismissButton.tsx b/packages/vkui/src/components/ModalDismissButton/ModalDismissButton.tsx index 64ce2011f1..db063687e2 100644 --- a/packages/vkui/src/components/ModalDismissButton/ModalDismissButton.tsx +++ b/packages/vkui/src/components/ModalDismissButton/ModalDismissButton.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; import { Icon20Cancel } from '@vkontakte/icons'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Tappable } from '../Tappable/Tappable'; import styles from './ModalDismissButton.module.css'; -export type ModalDismissButtonProps = React.HTMLAttributes; +export type ModalDismissButtonProps = HTMLAttributesWithRootRef; /** * @see https://vkcom.github.io/VKUI/#/ModalDismissButton diff --git a/packages/vkui/src/components/ModalPage/ModalPage.tsx b/packages/vkui/src/components/ModalPage/ModalPage.tsx index 27782c00df..6d7cca5a40 100644 --- a/packages/vkui/src/components/ModalPage/ModalPage.tsx +++ b/packages/vkui/src/components/ModalPage/ModalPage.tsx @@ -9,9 +9,11 @@ import { getNavId, NavIdProps } from '../../lib/getNavId'; import { Platform } from '../../lib/platform'; import { multiRef } from '../../lib/utils'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; import { ModalDismissButton } from '../ModalDismissButton/ModalDismissButton'; import { ModalRootContext, useModalRegistry } from '../ModalRoot/ModalRootContext'; import { ModalType } from '../ModalRoot/types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { ModalPageContext } from './ModalPageContext'; import styles from './ModalPage.module.css'; @@ -21,7 +23,7 @@ const sizeClassName = { l: styles['ModalPage--size-l'], }; -export interface ModalPageProps extends React.HTMLAttributes, NavIdProps { +export interface ModalPageProps extends HTMLAttributesWithRootRef, NavIdProps { /** * Шапка модальной страницы, `` */ @@ -80,7 +82,6 @@ export const ModalPage = ({ nav, id: idProp, hideCloseButton = false, - className, ...restProps }: ModalPageProps) => { const generatingId = useId(); @@ -108,19 +109,18 @@ export const ModalPage = ({ return ( - - + ); }; diff --git a/packages/vkui/src/components/Pagination/Pagination.tsx b/packages/vkui/src/components/Pagination/Pagination.tsx index fdbbb10d01..3554558593 100644 --- a/packages/vkui/src/components/Pagination/Pagination.tsx +++ b/packages/vkui/src/components/Pagination/Pagination.tsx @@ -1,16 +1,15 @@ import * as React from 'react'; import { Icon24ChevronCompactLeft, Icon24ChevronCompactRight } from '@vkontakte/icons'; import { PaginationPageType, usePagination } from '../../hooks/usePagination'; -import type { HasRootRef } from '../../types'; +import type { HTMLAttributesWithRootRef } from '../../types'; import { Button } from '../Button/Button'; +import { RootComponent } from '../RootComponent/RootComponent'; import { PaginationPageButton } from './PaginationPage/PaginationPageButton'; import { PaginationPageEllipsis } from './PaginationPage/PaginationPageEllipsis'; import { getPageAriaLabelDefault } from './utils'; import styles from './Pagination.module.css'; -export interface PaginationProps - extends Omit, 'onChange'>, - HasRootRef { +export interface PaginationProps extends Omit, 'onChange'> { /** * Текущая страница. */ @@ -61,7 +60,6 @@ export const Pagination = ({ getPageAriaLabel = getPageAriaLabelDefault, prevButtonAriaLabel = 'Перейти на предыдущую страницу', nextButtonAriaLabel = 'Перейти на следующую страницу', - getRootRef, onChange, ...resetProps }: PaginationProps) => { @@ -125,7 +123,12 @@ export const Pagination = ({ ); return ( - + ); }; diff --git a/packages/vkui/src/components/Panel/Panel.tsx b/packages/vkui/src/components/Panel/Panel.tsx index de320b343b..21a673fafb 100644 --- a/packages/vkui/src/components/Panel/Panel.tsx +++ b/packages/vkui/src/components/Panel/Panel.tsx @@ -5,7 +5,8 @@ import { usePlatform } from '../../hooks/usePlatform'; import { SizeType } from '../../lib/adaptivity'; import { NavIdProps } from '../../lib/getNavId'; import { Platform } from '../../lib/platform'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { TooltipContainer } from '../Tooltip/TooltipContainer'; import { Touch } from '../Touch/Touch'; import styles from './Panel.module.css'; @@ -16,36 +17,24 @@ const sizeXClassNames = { [SizeType.REGULAR]: styles['Panel--sizeX-regular'], }; -export interface PanelProps - extends React.HTMLAttributes, - HasRootRef, - NavIdProps { +export interface PanelProps extends HTMLAttributesWithRootRef, NavIdProps { centered?: boolean; } /** * @see https://vkcom.github.io/VKUI/#/Panel */ -export const Panel = ({ - centered = false, - children, - getRootRef, - nav, - className, - ...restProps -}: PanelProps) => { +export const Panel = ({ centered = false, children, nav, ...restProps }: PanelProps) => { const platform = usePlatform(); const { sizeX = 'none' } = useAdaptivity(); return ( -
}
-
+ ); }; diff --git a/packages/vkui/src/components/PanelHeader/PanelHeader.tsx b/packages/vkui/src/components/PanelHeader/PanelHeader.tsx index 15516547c2..a53861a00a 100644 --- a/packages/vkui/src/components/PanelHeader/PanelHeader.tsx +++ b/packages/vkui/src/components/PanelHeader/PanelHeader.tsx @@ -5,10 +5,11 @@ import { useAdaptivityConditionalRender } from '../../hooks/useAdaptivityConditi import { usePlatform } from '../../hooks/usePlatform'; import { SizeType } from '../../lib/adaptivity'; import { Platform } from '../../lib/platform'; -import { HasComponent, HasRef, HasRootRef } from '../../types'; +import { HasComponent, HasRef, HTMLAttributesWithRootRef } from '../../types'; import { useConfigProvider } from '../ConfigProvider/ConfigProviderContext'; import { FixedLayout } from '../FixedLayout/FixedLayout'; import { ModalRootContext } from '../ModalRoot/ModalRootContext'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Separator } from '../Separator/Separator'; import { Spacing } from '../Spacing/Spacing'; import { TooltipContainer } from '../Tooltip/TooltipContainer'; @@ -28,9 +29,8 @@ const sizeXClassNames = { }; export interface PanelHeaderProps - extends React.HTMLAttributes, - HasRef, - HasRootRef { + extends HTMLAttributesWithRootRef, + HasRef { before?: React.ReactNode; /** * Добавляет элемент справа. @@ -132,7 +132,6 @@ export const PanelHeader = ({ getRef, getRootRef, fixed, - className, typographyProps, ...restProps }: PanelHeaderProps) => { @@ -142,9 +141,9 @@ export const PanelHeader = ({ let isFixed = fixed !== undefined ? fixed : platform !== Platform.VKCOM; return ( -
{isFixed ? ( )} -
+ ); }; diff --git a/packages/vkui/src/components/PanelHeaderContent/PanelHeaderContent.tsx b/packages/vkui/src/components/PanelHeaderContent/PanelHeaderContent.tsx index 2279decc00..8da28a189f 100644 --- a/packages/vkui/src/components/PanelHeaderContent/PanelHeaderContent.tsx +++ b/packages/vkui/src/components/PanelHeaderContent/PanelHeaderContent.tsx @@ -2,7 +2,8 @@ import * as React from 'react'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; import { usePlatform } from '../../hooks/usePlatform'; import { Platform } from '../../lib/platform'; -import { HasChildren } from '../../types'; +import { HasChildren, HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable } from '../Tappable/Tappable'; import { Footnote } from '../Typography/Footnote/Footnote'; import { Headline } from '../Typography/Headline/Headline'; @@ -15,7 +16,7 @@ const platformClassNames = { vkcom: styles['PanelHeaderContent--vkcom'], }; -export interface PanelHeaderContentProps extends React.HTMLAttributes { +export interface PanelHeaderContentProps extends HTMLAttributesWithRootRef { aside?: React.ReactNode; before?: React.ReactNode; status?: React.ReactNode; @@ -49,8 +50,6 @@ const PanelHeaderChildren = ({ hasStatus, hasBefore, children }: PanelHeaderChil * @see https://vkcom.github.io/VKUI/#/PanelHeaderContent */ export const PanelHeaderContent = ({ - className, - style, aside, status, before, @@ -72,15 +71,13 @@ export const PanelHeaderContent = ({ : {}; return ( -
{hasReactNode(before) &&
{before}
} @@ -104,6 +101,6 @@ export const PanelHeaderContent = ({
{hasReactNode(before) &&
} -
+ ); }; diff --git a/packages/vkui/src/components/PanelHeaderContext/PanelHeaderContext.tsx b/packages/vkui/src/components/PanelHeaderContext/PanelHeaderContext.tsx index 670abcbd29..bf08ba243e 100644 --- a/packages/vkui/src/components/PanelHeaderContext/PanelHeaderContext.tsx +++ b/packages/vkui/src/components/PanelHeaderContext/PanelHeaderContext.tsx @@ -8,6 +8,7 @@ import { SizeType } from '../../lib/adaptivity'; import { useDOM } from '../../lib/dom'; import { Platform } from '../../lib/platform'; import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect'; +import { HTMLAttributesWithRootRef } from '../../types'; import { useScrollLock } from '../AppRoot/ScrollContext'; import { FixedLayout } from '../FixedLayout/FixedLayout'; import styles from './PanelHeaderContext.module.css'; @@ -18,7 +19,7 @@ const sizeXClassNames = { [SizeType.REGULAR]: styles['PanelHeaderContext--sizeX-regular'], }; -export interface PanelHeaderContextProps extends React.HTMLAttributes { +export interface PanelHeaderContextProps extends HTMLAttributesWithRootRef { opened: boolean; onClose: VoidFunction; } diff --git a/packages/vkui/src/components/Placeholder/Placeholder.tsx b/packages/vkui/src/components/Placeholder/Placeholder.tsx index 195b357d89..a1b583c3d0 100644 --- a/packages/vkui/src/components/Placeholder/Placeholder.tsx +++ b/packages/vkui/src/components/Placeholder/Placeholder.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Headline } from '../Typography/Headline/Headline'; import { Title } from '../Typography/Title/Title'; import styles from './Placeholder.module.css'; -export interface PlaceholderProps - extends React.HTMLAttributes, - HasRootRef { +export interface PlaceholderProps extends HTMLAttributesWithRootRef { /** * Иконка */ @@ -39,19 +38,15 @@ export const Placeholder = ({ action, children, stretched, - getRootRef, - className, withPadding = true, ...restProps }: PlaceholderProps) => ( -
{hasReactNode(icon) &&
{icon}
} @@ -66,5 +61,5 @@ export const Placeholder = ({ )} {hasReactNode(action) &&
{action}
} -
+ ); diff --git a/packages/vkui/src/components/PopoutRoot/PopoutRoot.tsx b/packages/vkui/src/components/PopoutRoot/PopoutRoot.tsx index 3499b2a52e..4a6d6646f6 100644 --- a/packages/vkui/src/components/PopoutRoot/PopoutRoot.tsx +++ b/packages/vkui/src/components/PopoutRoot/PopoutRoot.tsx @@ -1,41 +1,32 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; import { blurActiveElement, useDOM } from '../../lib/dom'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { AppRootPortal } from '../AppRoot/AppRootPortal'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './PopoutRoot.module.css'; interface PopoutRootPopoutProps { children: React.ReactNode; } -const PopoutRootPopout = ({ children }: PopoutRootPopoutProps) => { - return
{children}
; -}; +const PopoutRootPopout = (props: PopoutRootPopoutProps) => ( +
+); interface PopoutRootModalProps { children: React.ReactNode; } -const PopoutRootModal = ({ children }: PopoutRootModalProps) => { - return
{children}
; -}; +const PopoutRootModal = (props: PopoutRootModalProps) => ( +
+); -export interface PopoutRootProps - extends React.HTMLAttributes, - HasRootRef { +export interface PopoutRootProps extends HTMLAttributesWithRootRef { popout?: React.ReactNode; modal?: React.ReactNode; } -export const PopoutRoot = ({ - popout, - modal, - children, - getRootRef, - className, - ...restProps -}: PopoutRootProps) => { +export const PopoutRoot = ({ popout, modal, children, ...restProps }: PopoutRootProps) => { const { document } = useDOM(); React.useEffect(() => { @@ -43,12 +34,12 @@ export const PopoutRoot = ({ }, [document, popout]); return ( -
+ {children} {!!popout && {popout}} {!!modal && {modal}} -
+ ); }; diff --git a/packages/vkui/src/components/PopoutWrapper/PopoutWrapper.tsx b/packages/vkui/src/components/PopoutWrapper/PopoutWrapper.tsx index 1eac896487..8ab22a0f45 100644 --- a/packages/vkui/src/components/PopoutWrapper/PopoutWrapper.tsx +++ b/packages/vkui/src/components/PopoutWrapper/PopoutWrapper.tsx @@ -5,6 +5,8 @@ import { usePlatform } from '../../hooks/usePlatform'; import { useTimeout } from '../../hooks/useTimeout'; import { useDOM } from '../../lib/dom'; import { Platform } from '../../lib/platform'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './PopoutWrapper.module.css'; const stylesAlignX = { @@ -19,7 +21,7 @@ const stylesAlignY = { bottom: styles['PopoutWrapper--alignY-bottom'], }; -export interface PopoutWrapperProps extends React.HTMLAttributes { +export interface PopoutWrapperProps extends HTMLAttributesWithRootRef { hasMask?: boolean; fixed?: boolean; alignY?: 'top' | 'center' | 'bottom'; @@ -38,12 +40,10 @@ export const PopoutWrapper = ({ fixed = true, children, onClick, - className, ...restProps }: PopoutWrapperProps) => { const platform = usePlatform(); const [opened, setOpened] = React.useState(!hasMask); - const elRef = React.useRef(null); const onFadeInEnd = (e?: React.AnimationEvent) => { if (!e || e.animationName === styles['animation-full-fade-in']) { @@ -61,9 +61,9 @@ export const PopoutWrapper = ({ }); return ( -
{children}
-
+ ); }; diff --git a/packages/vkui/src/components/Popper/Popper.tsx b/packages/vkui/src/components/Popper/Popper.tsx index 00a97e3151..df2eabe76d 100644 --- a/packages/vkui/src/components/Popper/Popper.tsx +++ b/packages/vkui/src/components/Popper/Popper.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; import { useExternRef } from '../../hooks/useExternRef'; import { arrowMiddleware, @@ -17,7 +16,7 @@ import { useFloating, type UseFloatingMiddleware, } from '../../lib/floating'; -import type { HasRef } from '../../types'; +import type { HasRef, HTMLAttributesWithRootRef } from '../../types'; import { AppRootPortal } from '../AppRoot/AppRootPortal'; import { DEFAULT_ARROW_HEIGHT, @@ -25,6 +24,7 @@ import { DefaultIcon, } from '../PopperArrow/DefaultIcon'; import { PopperArrow, type PopperArrowProps } from '../PopperArrow/PopperArrow'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Popper.module.css'; export interface PopperRenderContentProps { @@ -32,7 +32,7 @@ export interface PopperRenderContentProps { } export interface PopperCommonProps - extends React.HTMLAttributes, + extends HTMLAttributesWithRootRef, HasRef { /** * По умолчанию компонент выберет наилучшее расположение сам. Но его можно задать извне с помощью этого свойства @@ -133,7 +133,7 @@ export const Popper = ({ style: styleProp, customMiddlewares, renderContent, - className, + getRootRef, ...restProps }: PopperProps) => { const [arrowRef, setArrowRef] = React.useState(null); @@ -216,7 +216,8 @@ export const Popper = ({ }, }); - const handleRootRef = useExternRef(refs.setFloating, getRef); + // TODO [>=6]: убрать getRef + const handleRootRef = useExternRef(refs.setFloating, getRef, getRootRef); React.useEffect(() => { refs.setReference(targetRef.current); @@ -229,10 +230,10 @@ export const Popper = ({ }, [onPlacementChange, resolvedPlacement]); const dropdown = ( -
)} {renderContent ? renderContent({ className: '' }) : children} -
+ ); return ( diff --git a/packages/vkui/src/components/Progress/Progress.tsx b/packages/vkui/src/components/Progress/Progress.tsx index f2e03c45ab..295f8ee028 100644 --- a/packages/vkui/src/components/Progress/Progress.tsx +++ b/packages/vkui/src/components/Progress/Progress.tsx @@ -1,7 +1,8 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { clamp } from '../../helpers/math'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Progress.module.css'; const stylesAppearance = { @@ -26,9 +27,7 @@ function progressStyle(height: number | undefined, styleProps: React.CSSProperti return style; } -export interface ProgressProps - extends React.HTMLAttributes, - HasRootRef { +export interface ProgressProps extends HTMLAttributesWithRootRef { /** * Стиль отображения прогрессбара */ @@ -48,8 +47,6 @@ const PROGRESS_MAX_VALUE = 100; */ export const Progress = ({ value = 0, - getRootRef, - className, appearance = 'accent', height, style: styleProps, @@ -61,7 +58,7 @@ export const Progress = ({ const style = progressStyle(height, styleProps); return ( -
-
+ ); }; diff --git a/packages/vkui/src/components/PromoBanner/PromoBanner.tsx b/packages/vkui/src/components/PromoBanner/PromoBanner.tsx index 87c0f9b87a..e1cb3f1fcc 100644 --- a/packages/vkui/src/components/PromoBanner/PromoBanner.tsx +++ b/packages/vkui/src/components/PromoBanner/PromoBanner.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { Icon24Dismiss } from '@vkontakte/icons'; -import { classNames } from '@vkontakte/vkjs'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Button } from '../Button/Button'; import { Image } from '../Image/Image'; +import { RootComponent } from '../RootComponent/RootComponent'; import { SimpleCell } from '../SimpleCell/SimpleCell'; import { Footnote } from '../Typography/Footnote/Footnote'; import styles from './PromoBanner.module.css'; @@ -37,7 +38,7 @@ type BannerData = { ageRestrictions?: string; }; -export interface PromoBannerProps extends React.HTMLAttributes { +export interface PromoBannerProps extends HTMLAttributesWithRootRef { /** Данные рекламного баннера, полученные из VKWebAppGetAds */ bannerData: BannerData; /** Флаг скрытия кнопки закрытия рекламы */ @@ -58,7 +59,6 @@ export const PromoBanner = ({ bannerData = {}, onClose, isCloseButtonHidden, - className, ...restProps }: PromoBannerProps) => { if (process.env.NODE_ENV === 'development') { @@ -89,7 +89,7 @@ export const PromoBanner = ({ }, [statsPixels.playbackStarted]); return ( -
+
{bannerData.advertisingLabel || 'Advertisement'} {bannerData.ageRestrictions && ( @@ -137,6 +137,6 @@ export const PromoBanner = ({
)} -
+ ); }; diff --git a/packages/vkui/src/components/PullToRefresh/PullToRefreshSpinner.tsx b/packages/vkui/src/components/PullToRefresh/PullToRefreshSpinner.tsx index 73f99e4c53..443af3f9a6 100644 --- a/packages/vkui/src/components/PullToRefresh/PullToRefreshSpinner.tsx +++ b/packages/vkui/src/components/PullToRefresh/PullToRefreshSpinner.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './PullToRefresh.module.css'; function calcStrokeDashOffset(value: number, radius: number) { @@ -7,21 +9,20 @@ function calcStrokeDashOffset(value: number, radius: number) { return 2 * Math.PI * radius * (1 - progress); } -export interface PullToRefreshSpinnerProps extends React.HTMLAttributes { - 'size'?: number; - 'strokeWidth'?: number; - 'on'?: boolean; - 'progress'?: number; - 'aria-label'?: string; +export interface PullToRefreshSpinnerProps extends HTMLAttributesWithRootRef { + size?: number; + strokeWidth?: number; + on?: boolean; + progress?: number; } export const PullToRefreshSpinner = ({ on = true, size = 24, strokeWidth = 2.5, - style, progress = 0, 'aria-label': ariaLabel = 'Пожалуйста, подождите...', + ...restProps }: PullToRefreshSpinnerProps) => { const radius = 0.5 * size - 0.5 * strokeWidth; const dasharray = 2 * Math.PI * radius; @@ -30,13 +31,13 @@ export const PullToRefreshSpinner = ({ const dashoffset = calcStrokeDashOffset(on ? 80 : progress, radius); return ( -
-
+ ); }; diff --git a/packages/vkui/src/components/RadioGroup/RadioGroup.tsx b/packages/vkui/src/components/RadioGroup/RadioGroup.tsx index 3820658845..9ea46f9b81 100644 --- a/packages/vkui/src/components/RadioGroup/RadioGroup.tsx +++ b/packages/vkui/src/components/RadioGroup/RadioGroup.tsx @@ -1,29 +1,23 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './RadioGroup.module.css'; -export interface RadioGroupProps extends React.HTMLAttributes { +export interface RadioGroupProps extends HTMLAttributesWithRootRef { mode?: 'vertical' | 'horizontal'; } /** * @see https://vkcom.github.io/VKUI/#/RadioGroup */ -export const RadioGroup = ({ - mode = 'vertical', - children, - className, - ...restProps -}: RadioGroupProps) => ( -
( + - {children} -
+ /> ); diff --git a/packages/vkui/src/components/Removable/Removable.tsx b/packages/vkui/src/components/Removable/Removable.tsx index 884ef5e9e6..738c931bf5 100644 --- a/packages/vkui/src/components/Removable/Removable.tsx +++ b/packages/vkui/src/components/Removable/Removable.tsx @@ -1,14 +1,14 @@ import * as React from 'react'; import { Icon24Cancel } from '@vkontakte/icons'; import { classNames, noop } from '@vkontakte/vkjs'; -import { useExternRef } from '../../hooks/useExternRef'; import { useGlobalEventListener } from '../../hooks/useGlobalEventListener'; import { usePlatform } from '../../hooks/usePlatform'; import { useDOM } from '../../lib/dom'; import { Platform } from '../../lib/platform'; import { getTitleFromChildren } from '../../lib/utils'; -import { HasChildren, HasRootRef } from '../../types'; +import { HasChildren, HTMLAttributesWithRootRef } from '../../types'; import { IconButton } from '../IconButton/IconButton'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable } from '../Tappable/Tappable'; import styles from './Removable.module.css'; @@ -106,10 +106,7 @@ const RemovableIos = ({ ); }; -interface RemovableOwnProps - extends React.HTMLAttributes, - RemovableProps, - HasRootRef { +interface RemovableOwnProps extends HTMLAttributesWithRootRef, RemovableProps { /** * Расположение кнопки удаления. */ @@ -125,19 +122,15 @@ interface RemovableOwnProps * @see https://vkcom.github.io/VKUI/#/Removable */ export const Removable = ({ - getRootRef, children, onRemove = noop, removePlaceholder = 'Удалить', align = 'center', - className, indent = false, ...restProps }: RemovableOwnProps) => { const platform = usePlatform(); - const ref = useExternRef(getRootRef); - const onRemoveClick = (e: React.MouseEvent) => { e.preventDefault(); onRemove(e); @@ -146,14 +139,12 @@ export const Removable = ({ const removePlaceholderString: string = getTitleFromChildren(removePlaceholder); return ( -
{platform !== Platform.IOS && ( @@ -183,6 +174,6 @@ export const Removable = ({ {children} )} -
+ ); }; diff --git a/packages/vkui/src/components/RichCell/RichCellIcon/RichCellIcon.tsx b/packages/vkui/src/components/RichCell/RichCellIcon/RichCellIcon.tsx index e687a44a20..d7250e4d70 100644 --- a/packages/vkui/src/components/RichCell/RichCellIcon/RichCellIcon.tsx +++ b/packages/vkui/src/components/RichCell/RichCellIcon/RichCellIcon.tsx @@ -1,15 +1,10 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../../types'; +import { RootComponent } from '../../RootComponent/RootComponent'; import styles from './RichCellIcon.module.css'; -export const RichCellIcon = ({ - children, - className, - ...restProps -}: React.HTMLAttributes) => { - return ( -
- {children} -
- ); +export type RichCellIconProps = HTMLAttributesWithRootRef; + +export const RichCellIcon = (props: RichCellIconProps) => { + return ; }; diff --git a/packages/vkui/src/components/Root/Root.tsx b/packages/vkui/src/components/Root/Root.tsx index 5f41a6eaf2..7988f48e0d 100644 --- a/packages/vkui/src/components/Root/Root.tsx +++ b/packages/vkui/src/components/Root/Root.tsx @@ -7,14 +7,16 @@ import { getNavId, NavIdProps } from '../../lib/getNavId'; import { Platform } from '../../lib/platform'; import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; import { ScrollContext } from '../AppRoot/ScrollContext'; import { useConfigProvider } from '../ConfigProvider/ConfigProviderContext'; import { NavTransitionProvider } from '../NavTransitionContext/NavTransitionContext'; import { NavTransitionDirectionProvider } from '../NavTransitionDirectionContext/NavTransitionDirectionContext'; +import { RootComponent } from '../RootComponent/RootComponent'; import { SplitColContext } from '../SplitCol/SplitColContext'; import styles from './Root.module.css'; -export interface RootProps extends React.HTMLAttributes, NavIdProps { +export interface RootProps extends HTMLAttributesWithRootRef, NavIdProps { activeView: string; onTransition?(params: { isBack: boolean; from: string; to: string }): void; children: React.ReactElement | Iterable; @@ -37,7 +39,6 @@ export const Root = ({ activeView: _activeView, onTransition, nav, - className, ...restProps }: RootProps) => { const scroll = React.useContext(ScrollContext); @@ -116,13 +117,12 @@ export const Root = ({ }; return ( -
{views.map((view) => { @@ -161,6 +161,6 @@ export const Root = ({
); })} -
+ ); }; diff --git a/packages/vkui/src/components/RootComponent/RootComponent.test.tsx b/packages/vkui/src/components/RootComponent/RootComponent.test.tsx new file mode 100644 index 0000000000..0858912aa0 --- /dev/null +++ b/packages/vkui/src/components/RootComponent/RootComponent.test.tsx @@ -0,0 +1,6 @@ +import { baselineComponent } from '../../testing/utils'; +import { RootComponent } from './RootComponent'; + +describe('RootComponent', () => { + baselineComponent(RootComponent); +}); diff --git a/packages/vkui/src/components/RootComponent/RootComponent.tsx b/packages/vkui/src/components/RootComponent/RootComponent.tsx new file mode 100644 index 0000000000..d97c75ab63 --- /dev/null +++ b/packages/vkui/src/components/RootComponent/RootComponent.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { classNames } from '@vkontakte/vkjs'; +import { HasComponent, HasRootRef } from '../../types'; + +export interface RootComponentProps + extends React.AllHTMLAttributes, + HasRootRef, + HasComponent { + baseClassName?: string; +} + +/** + * Базовый корневой компонент. + */ +export const RootComponent = ({ + Component = 'div', + baseClassName, + className, + getRootRef, + ...restProps +}: RootComponentProps) => ( + +); diff --git a/packages/vkui/src/components/ScrollArrow/ScrollArrow.tsx b/packages/vkui/src/components/ScrollArrow/ScrollArrow.tsx index 95fed3cb49..b62c3cbbf0 100644 --- a/packages/vkui/src/components/ScrollArrow/ScrollArrow.tsx +++ b/packages/vkui/src/components/ScrollArrow/ScrollArrow.tsx @@ -7,6 +7,7 @@ import { } from '@vkontakte/icons'; import { classNames } from '@vkontakte/vkjs'; import { HasRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './ScrollArrow.module.css'; const stylesSize = { @@ -54,25 +55,22 @@ export const ScrollArrow = ({ size = 'l', offsetY, direction, - className, - getRootRef, children = , ...restProps }: ScrollArrowProps) => { return ( - + ); }; diff --git a/packages/vkui/src/components/Search/Search.tsx b/packages/vkui/src/components/Search/Search.tsx index a82ab52af7..8611365a27 100644 --- a/packages/vkui/src/components/Search/Search.tsx +++ b/packages/vkui/src/components/Search/Search.tsx @@ -9,7 +9,7 @@ import { usePlatform } from '../../hooks/usePlatform'; import { SizeType } from '../../lib/adaptivity'; import { Platform } from '../../lib/platform'; import { touchEnabled, VKUITouchEvent } from '../../lib/touch'; -import { HasRef } from '../../types'; +import { HasRef, HasRootRef } from '../../types'; import { Button } from '../Button/Button'; import { IconButton } from '../IconButton/IconButton'; import { TouchEvent } from '../Touch/Touch'; @@ -18,6 +18,7 @@ import styles from './Search.module.css'; export interface SearchProps extends React.InputHTMLAttributes, + HasRootRef, HasRef { /** * iOS only. Текст кнопки "отмена", которая чистит текстовое поле и убирает фокус. @@ -54,6 +55,7 @@ export const Search = ({ iconAriaLabel, clearAriaLabel = 'Очистить', noPadding, + getRootRef, ...inputProps }: SearchProps) => { const inputRef = useExternRef(getRef); @@ -124,6 +126,7 @@ export const Search = ({ !noPadding && styles['Search--withPadding'], className, )} + ref={getRootRef} style={style} >
diff --git a/packages/vkui/src/components/SegmentedControl/SegmentedControl.tsx b/packages/vkui/src/components/SegmentedControl/SegmentedControl.tsx index ecaee28f1c..5c25be2e79 100644 --- a/packages/vkui/src/components/SegmentedControl/SegmentedControl.tsx +++ b/packages/vkui/src/components/SegmentedControl/SegmentedControl.tsx @@ -6,7 +6,8 @@ import { useId } from '../../hooks/useId'; import { SizeType } from '../../lib/adaptivity'; import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect'; import { warnOnce } from '../../lib/warnOnce'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { SegmentedControlOption } from './SegmentedControlOption/SegmentedControlOption'; import styles from './SegmentedControl.module.css'; @@ -24,8 +25,7 @@ export interface SegmentedControlOptionInterface } export interface SegmentedControlProps - extends Omit, 'onChange'>, - HasRootRef { + extends Omit, 'onChange'> { options: SegmentedControlOptionInterface[]; size?: 'm' | 'l'; name?: string; @@ -43,10 +43,8 @@ export const SegmentedControl = ({ size = 'l', name, options, - getRootRef, defaultValue = options[0]?.value, children, - className, onChange: onChangeProp, value: valueProp, ...restProps @@ -72,15 +70,13 @@ export const SegmentedControl = ({ const translateX = `translateX(${100 * actualIndex}%)`; return ( -
{actualIndex > -1 && ( @@ -107,6 +103,6 @@ export const SegmentedControl = ({ ))}
-
+ ); }; diff --git a/packages/vkui/src/components/SegmentedControl/SegmentedControlOption/SegmentedControlOption.tsx b/packages/vkui/src/components/SegmentedControl/SegmentedControlOption/SegmentedControlOption.tsx index 056ef8be8e..be4901bd06 100644 --- a/packages/vkui/src/components/SegmentedControl/SegmentedControlOption/SegmentedControlOption.tsx +++ b/packages/vkui/src/components/SegmentedControl/SegmentedControlOption/SegmentedControlOption.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { useFocusVisible } from '../../../hooks/useFocusVisible'; import { callMultiple } from '../../../lib/callMultiple'; -import { HasRef } from '../../../types'; +import { HasRef, HasRootRef } from '../../../types'; import { FocusVisible } from '../../FocusVisible/FocusVisible'; import { Headline } from '../../Typography/Headline/Headline'; import { VisuallyHidden } from '../../VisuallyHidden/VisuallyHidden'; @@ -10,6 +10,7 @@ import styles from './SegmentedControlOption.module.css'; export interface SegmentedControlOptionProps extends React.InputHTMLAttributes, + HasRootRef, HasRef {} /** @@ -20,6 +21,7 @@ export const SegmentedControlOption = ({ className, style, children, + getRootRef, ...restProps }: SegmentedControlOptionProps) => { const { focusVisible, onBlur, onFocus } = useFocusVisible(); @@ -31,6 +33,7 @@ export const SegmentedControlOption = ({ restProps.checked && styles['SegmentedControlOption--checked'], className, )} + ref={getRootRef} style={style} > , + extends HTMLAttributesWithRootRef, HasAlign, - HasRootRef, Pick { multiline?: boolean; disabled?: boolean; diff --git a/packages/vkui/src/components/SelectTypography/SelectTypography.tsx b/packages/vkui/src/components/SelectTypography/SelectTypography.tsx index 2580e242bc..915a1c03ee 100644 --- a/packages/vkui/src/components/SelectTypography/SelectTypography.tsx +++ b/packages/vkui/src/components/SelectTypography/SelectTypography.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; -import { HasChildren } from '../../types'; +import { HasChildren, HTMLAttributesWithRootRef } from '../../types'; import type { SelectType } from '../Select/Select'; import { Text } from '../Typography/Text/Text'; -export interface SelectTypographyProps extends React.HTMLAttributes, HasChildren { +export interface SelectTypographyProps + extends HTMLAttributesWithRootRef, + HasChildren { selectType?: SelectType; } diff --git a/packages/vkui/src/components/Separator/Separator.tsx b/packages/vkui/src/components/Separator/Separator.tsx index 185c502852..4edc0c8175 100644 --- a/packages/vkui/src/components/Separator/Separator.tsx +++ b/packages/vkui/src/components/Separator/Separator.tsx @@ -1,8 +1,10 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Separator.module.css'; -export interface SeparatorProps extends React.HTMLAttributes { +export interface SeparatorProps extends HTMLAttributesWithRootRef { /** * С этим свойством компонент не будет иметь отступы слева и справа */ @@ -12,11 +14,11 @@ export interface SeparatorProps extends React.HTMLAttributes { /** * @see https://vkcom.github.io/VKUI/#/Separator */ -export const Separator = ({ wide, className, ...restProps }: SeparatorProps) => ( -
( +
-
+ ); diff --git a/packages/vkui/src/components/Slider/Slider.tsx b/packages/vkui/src/components/Slider/Slider.tsx index 531daf44f7..f6d4f32dda 100644 --- a/packages/vkui/src/components/Slider/Slider.tsx +++ b/packages/vkui/src/components/Slider/Slider.tsx @@ -4,7 +4,7 @@ import { clamp } from '../../helpers/math'; import { useAdaptivity } from '../../hooks/useAdaptivity'; import { useExternRef } from '../../hooks/useExternRef'; import { SizeType } from '../../lib/adaptivity'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; import { Touch, type TouchEvent, type TouchEventHandler } from '../Touch/Touch'; import { SliderThumb } from './SliderThumb/SliderThumb'; import { @@ -26,8 +26,7 @@ const sizeYClassNames = { }; export interface SliderBaseProps - extends HasRootRef, - Omit, 'value' | 'defaultValue' | 'onChange'> { + extends Omit, 'value' | 'defaultValue' | 'onChange'> { min?: number; max?: number; step?: number; diff --git a/packages/vkui/src/components/Snackbar/Snackbar.tsx b/packages/vkui/src/components/Snackbar/Snackbar.tsx index bd7dd70870..3391d297e5 100644 --- a/packages/vkui/src/components/Snackbar/Snackbar.tsx +++ b/packages/vkui/src/components/Snackbar/Snackbar.tsx @@ -7,8 +7,10 @@ import { useWaitTransitionFinish } from '../../hooks/useWaitTransitionFinish'; import { ViewWidth } from '../../lib/adaptivity'; import { Platform } from '../../lib/platform'; import { rubber } from '../../lib/touch'; +import { HTMLAttributesWithRootRef } from '../../types'; import { AppRootPortal } from '../AppRoot/AppRootPortal'; import { Button } from '../Button/Button'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Touch, TouchEvent } from '../Touch/Touch'; import { Paragraph } from '../Typography/Paragraph/Paragraph'; import { Subhead } from '../Typography/Subhead/Subhead'; @@ -19,7 +21,7 @@ const stylesLayout = { horizontal: styles['Snackbar--layout-horizontal'], }; -export interface SnackbarProps extends React.HTMLAttributes { +export interface SnackbarProps extends HTMLAttributesWithRootRef { /** * Название кнопки действия в уведомлении * Не может использоваться одновременно с `subtitle` @@ -83,7 +85,6 @@ export const Snackbar = ({ onActionClick, onClose, mode = 'default', - className, subtitle, offsetY, style, @@ -203,9 +204,9 @@ export const Snackbar = ({ return ( -
@@ -250,7 +250,7 @@ export const Snackbar = ({ {after &&
{after}
}
-
+ ); }; diff --git a/packages/vkui/src/components/Spacing/Spacing.tsx b/packages/vkui/src/components/Spacing/Spacing.tsx index 86e6993b26..13a402e7bc 100644 --- a/packages/vkui/src/components/Spacing/Spacing.tsx +++ b/packages/vkui/src/components/Spacing/Spacing.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; -import { HasChildren } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Spacing.module.css'; -export interface SpacingProps extends React.HTMLAttributes, HasChildren { +export interface SpacingProps extends HTMLAttributesWithRootRef { /** * Высота спэйсинга */ @@ -13,12 +13,12 @@ export interface SpacingProps extends React.HTMLAttributes, HasC /** * @see https://vkcom.github.io/VKUI/#/Spacing */ -export const Spacing = ({ size = 8, style: styleProp, className, ...restProps }: SpacingProps) => { +export const Spacing = ({ size = 8, style: styleProp, ...restProps }: SpacingProps) => { const style: React.CSSProperties = { height: size, padding: `${size / 2}px 0`, ...styleProp, }; - return
; + return ; }; diff --git a/packages/vkui/src/components/Spinner/Spinner.tsx b/packages/vkui/src/components/Spinner/Spinner.tsx index 5253168d59..2cf0243c5b 100644 --- a/packages/vkui/src/components/Spinner/Spinner.tsx +++ b/packages/vkui/src/components/Spinner/Spinner.tsx @@ -1,11 +1,12 @@ import * as React from 'react'; import { Icon16Spinner, Icon24Spinner, Icon32Spinner, Icon44Spinner } from '@vkontakte/icons'; -import { classNames } from '@vkontakte/vkjs'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden'; import styles from './Spinner.module.css'; -export interface SpinnerProps extends React.HTMLAttributes { +export interface SpinnerProps extends HTMLAttributesWithRootRef { size?: 'small' | 'regular' | 'medium' | 'large'; disableAnimation?: boolean; } @@ -21,7 +22,6 @@ export const Spinner = React.memo( // TODO [>=6]: Удалить автоматическое приведение aria-label 'aria-label': ariaLabel = 'Загружается...', disableAnimation, - className, ...restProps }: SpinnerProps) => { const SpinnerIcon = { @@ -48,7 +48,12 @@ export const Spinner = React.memo( } return ( - + {!disableAnimation && ( // TODO [a11y]: use reduced motion hook? @@ -65,7 +70,7 @@ export const Spinner = React.memo( )} {children ?? ariaLabel} - + ); }, ); diff --git a/packages/vkui/src/components/SplitCol/SplitCol.tsx b/packages/vkui/src/components/SplitCol/SplitCol.tsx index f8271b9972..a57fa80e03 100644 --- a/packages/vkui/src/components/SplitCol/SplitCol.tsx +++ b/packages/vkui/src/components/SplitCol/SplitCol.tsx @@ -1,11 +1,14 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { useAdaptivity } from '../../hooks/useAdaptivity'; +import { useExternRef } from '../../hooks/useExternRef'; import { useMediaQueries } from '../../hooks/useMediaQueries'; import { useObjectMemo } from '../../hooks/useObjectMemo'; import { ViewWidth, viewWidthToClassName } from '../../lib/adaptivity'; import { matchMediaListAddListener, matchMediaListRemoveListener } from '../../lib/matchMedia'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { SplitColContext } from './SplitColContext'; import styles from './SplitCol.module.css'; @@ -45,7 +48,7 @@ function useTransitionAnimate(animateProp?: boolean) { return animate; } -export interface SplitColProps extends React.HTMLAttributes { +export interface SplitColProps extends HTMLAttributesWithRootRef { width?: number | string; maxWidth?: number | string; minWidth?: number | string; @@ -87,10 +90,10 @@ export const SplitCol = (props: SplitColProps) => { style, autoSpaced, stretchedOnMobile, - className, + getRootRef, ...restProps } = props; - const baseRef = React.useRef(null); + const baseRef = useExternRef(getRootRef); const { viewWidth } = useAdaptivity(); const animate = useTransitionAnimate(animateProp); @@ -105,7 +108,7 @@ export const SplitCol = (props: SplitColProps) => { } return ( -
{ maxWidth: maxWidth, minWidth: minWidth, }} - ref={baseRef} - className={classNames( + getRootRef={baseRef} + baseClassName={classNames( styles['SplitCol'], viewWidthToClassName(breakpointClassNames, viewWidth), spaced && classNames(styles['SplitCol--spaced'], 'vkuiInternalSplitCol--spaced'), @@ -124,12 +127,11 @@ export const SplitCol = (props: SplitColProps) => { classNames(styles['SplitCol--spaced-auto'], 'vkuiInternalSplitCol--spaced-auto'), fixed && styles['SplitCol--fixed'], stretchedOnMobile && styles['SplitCol--stretched-on-mobile'], - className, )} > {fixed ?
{children}
: children}
-
+ ); }; diff --git a/packages/vkui/src/components/SplitLayout/SplitLayout.tsx b/packages/vkui/src/components/SplitLayout/SplitLayout.tsx index 981e4a79db..7bad333c3b 100644 --- a/packages/vkui/src/components/SplitLayout/SplitLayout.tsx +++ b/packages/vkui/src/components/SplitLayout/SplitLayout.tsx @@ -2,13 +2,12 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { usePlatform } from '../../hooks/usePlatform'; import { Platform } from '../../lib/platform'; -import { HasRef, HasRootRef } from '../../types'; +import { HasRef, HTMLAttributesWithRootRef } from '../../types'; import { PopoutRoot } from '../PopoutRoot/PopoutRoot'; import styles from './SplitLayout.module.css'; export interface SplitLayoutProps - extends React.HTMLAttributes, - HasRootRef, + extends HTMLAttributesWithRootRef, HasRef { /** * Свойство для отрисовки `Alert`, `ActionSheet` и `ScreenSpinner`. diff --git a/packages/vkui/src/components/SubnavigationBar/SubnavigationBar.tsx b/packages/vkui/src/components/SubnavigationBar/SubnavigationBar.tsx index aaf55be027..4273acdd54 100644 --- a/packages/vkui/src/components/SubnavigationBar/SubnavigationBar.tsx +++ b/packages/vkui/src/components/SubnavigationBar/SubnavigationBar.tsx @@ -1,14 +1,15 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; +import { HTMLAttributesWithRootRef } from '../../types'; import { HorizontalScroll, HorizontalScrollProps, ScrollPositionHandler, } from '../HorizontalScroll/HorizontalScroll'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './SubnavigationBar.module.css'; export interface SubnavigationBarProps - extends React.HTMLAttributes, + extends HTMLAttributesWithRootRef, Pick< HorizontalScrollProps, 'showArrows' | 'getScrollToLeft' | 'getScrollToRight' | 'scrollAnimationDuration' @@ -30,7 +31,6 @@ export const SubnavigationBar = ({ getScrollToLeft = defaultScrollToLeft, getScrollToRight = defaultScrollToRight, scrollAnimationDuration, - className, ...restProps }: SubnavigationBarProps) => { let ScrollWrapper: React.ElementType; @@ -49,17 +49,14 @@ export const SubnavigationBar = ({ } return ( -
=6] + // Заменить у SubnavigationButton `display: inline-block` на `width: 100%` + // и удалить применение селектора в `SubnavigationButton.module.css`. + // 2. Заменить глобальный селектор на CSS Modules `styles['SubnavigationBar--mode-fixed']` + // mode !== 'fixed' && classNames('vkuiInternalSubnavigationBar--mode-fixed') + baseClassName={mode === 'fixed' ? 'vkuiInternalSubnavigationBar--mode-fixed' : undefined} {...restProps} - className={classNames( - // TODO: [>=6] - // Заменить у SubnavigationButton `display: inline-block` на `width: 100%` - // и удалить применение селектора в `SubnavigationButton.module.css`. - // 2. Заменить глобальный селектор на CSS Modules `styles['SubnavigationBar--mode-fixed']` - // mode !== 'fixed' && classNames('vkuiInternalSubnavigationBar--mode-fixed') - mode === 'fixed' && 'vkuiInternalSubnavigationBar--mode-fixed', - className, - )} >
    @@ -70,6 +67,6 @@ export const SubnavigationBar = ({ ))}
-
+ ); }; diff --git a/packages/vkui/src/components/Tabbar/Tabbar.tsx b/packages/vkui/src/components/Tabbar/Tabbar.tsx index b1d6a6bf78..2bcaa12e8b 100644 --- a/packages/vkui/src/components/Tabbar/Tabbar.tsx +++ b/packages/vkui/src/components/Tabbar/Tabbar.tsx @@ -2,9 +2,11 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { usePlatform } from '../../hooks/usePlatform'; import { Platform } from '../../lib/platform'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Tabbar.module.css'; -export interface TabbarProps extends React.HTMLAttributes { +export interface TabbarProps extends HTMLAttributesWithRootRef { /** * Флаг для показа/скрытия верхней тени (Android) или границы (iOS) */ @@ -34,22 +36,19 @@ const getItemsLayoutClassName = ( /** * @see https://vkcom.github.io/VKUI/#/Tabbar */ -export const Tabbar = ({ children, shadow = true, mode, className, ...restProps }: TabbarProps) => { +export const Tabbar = ({ shadow = true, mode, ...restProps }: TabbarProps) => { const platform = usePlatform(); return ( -
- {children} -
+ /> ); }; diff --git a/packages/vkui/src/components/TabbarItem/TabbarItem.tsx b/packages/vkui/src/components/TabbarItem/TabbarItem.tsx index a2304bbe50..d094201ec0 100644 --- a/packages/vkui/src/components/TabbarItem/TabbarItem.tsx +++ b/packages/vkui/src/components/TabbarItem/TabbarItem.tsx @@ -4,6 +4,7 @@ import { usePlatform } from '../../hooks/usePlatform'; import { Platform } from '../../lib/platform'; import { COMMON_WARNINGS, warnOnce } from '../../lib/warnOnce'; import { HasComponent, HasRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Tappable } from '../Tappable/Tappable'; import { Footnote } from '../Typography/Footnote/Footnote'; import styles from './TabbarItem.module.css'; @@ -36,8 +37,6 @@ export const TabbarItem = ({ href, Component = href ? 'a' : 'button', disabled, - className, - getRootRef, ...restProps }: TabbarItemProps) => { const platform = usePlatform(); @@ -51,17 +50,16 @@ export const TabbarItem = ({ } return ( - )}
-
+ ); }; diff --git a/packages/vkui/src/components/Tabs/Tabs.tsx b/packages/vkui/src/components/Tabs/Tabs.tsx index 78b5527a12..2b30dd1550 100644 --- a/packages/vkui/src/components/Tabs/Tabs.tsx +++ b/packages/vkui/src/components/Tabs/Tabs.tsx @@ -5,12 +5,11 @@ import { usePlatform } from '../../hooks/usePlatform'; import { pressedKey } from '../../lib/accessibility'; import { useDOM } from '../../lib/dom'; import { Platform } from '../../lib/platform'; -import { HasRootRef } from '../../types'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Tabs.module.css'; -export interface TabsProps - extends React.HTMLAttributes, - HasRootRef { +export interface TabsProps extends HTMLAttributesWithRootRef { mode?: 'default' | 'accent' | 'secondary'; } @@ -27,14 +26,7 @@ export const TabsModeContext = React.createContext({ /** * @see https://vkcom.github.io/VKUI/#/Tabs */ -export const Tabs = ({ - children, - mode = 'default', - getRootRef, - className, - role = 'tablist', - ...restProps -}: TabsProps) => { +export const Tabs = ({ children, mode = 'default', role = 'tablist', ...restProps }: TabsProps) => { const platform = usePlatform(); const { document } = useDOM(); @@ -137,22 +129,20 @@ export const Tabs = ({ }); return ( -
{children}
-
+ ); }; diff --git a/packages/vkui/src/components/TabsItem/TabsItem.tsx b/packages/vkui/src/components/TabsItem/TabsItem.tsx index 9969aad106..66d52de40a 100644 --- a/packages/vkui/src/components/TabsItem/TabsItem.tsx +++ b/packages/vkui/src/components/TabsItem/TabsItem.tsx @@ -3,6 +3,7 @@ import { classNames } from '@vkontakte/vkjs'; import { useAdaptivity } from '../../hooks/useAdaptivity'; import { SizeType } from '../../lib/adaptivity'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; import { TabsContextProps, TabsModeContext } from '../Tabs/Tabs'; import { Tappable } from '../Tappable/Tappable'; import { Headline } from '../Typography/Headline/Headline'; @@ -21,7 +22,7 @@ const stylesMode = { secondary: styles['TabsItem--mode-secondary'], }; -export interface TabsItemProps extends React.HTMLAttributes { +export interface TabsItemProps extends HTMLAttributesWithRootRef { /** * Добавляет иконку слева. * diff --git a/packages/vkui/src/components/TooltipBase/TooltipBase.tsx b/packages/vkui/src/components/TooltipBase/TooltipBase.tsx index f90a9d0e6e..87748982c6 100644 --- a/packages/vkui/src/components/TooltipBase/TooltipBase.tsx +++ b/packages/vkui/src/components/TooltipBase/TooltipBase.tsx @@ -3,6 +3,7 @@ import { classNames } from '@vkontakte/vkjs'; import { HasRootRef } from '../../types'; import { DefaultIcon } from '../PopperArrow/DefaultIcon'; import { PopperArrow, type PopperArrowProps } from '../PopperArrow/PopperArrow'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Subhead } from '../Typography/Subhead/Subhead'; import styles from './TooltipBase.module.css'; @@ -70,16 +71,14 @@ export const TooltipBase = ({ ArrowIcon = DefaultIcon, text, header, - className, ...restProps }: TooltipBaseProps) => { return ( -
@@ -97,6 +96,6 @@ export const TooltipBase = ({ {text && {text}}
-
+ ); }; diff --git a/packages/vkui/src/components/Typography/Typography.test.tsx b/packages/vkui/src/components/Typography/Typography.test.tsx new file mode 100644 index 0000000000..0ea23b0e8f --- /dev/null +++ b/packages/vkui/src/components/Typography/Typography.test.tsx @@ -0,0 +1,6 @@ +import { baselineComponent } from '../../testing/utils'; +import { Typography } from './Typography'; + +describe('Typography', () => { + baselineComponent(Typography); +}); diff --git a/packages/vkui/src/components/Typography/Typography.tsx b/packages/vkui/src/components/Typography/Typography.tsx index 3bdc32efa5..185b559a55 100644 --- a/packages/vkui/src/components/Typography/Typography.tsx +++ b/packages/vkui/src/components/Typography/Typography.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import { HasComponent, HasRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './Typography.module.css'; const stylesWeight = { @@ -28,21 +29,18 @@ export interface TypographyProps } export const Typography = ({ - className, weight, Component = 'span', normalize, - getRootRef, ...restProps }: TypographyProps) => ( - ); diff --git a/packages/vkui/src/components/UsersStack/UsersStack.tsx b/packages/vkui/src/components/UsersStack/UsersStack.tsx index bcab5910a0..dd2ffa457d 100644 --- a/packages/vkui/src/components/UsersStack/UsersStack.tsx +++ b/packages/vkui/src/components/UsersStack/UsersStack.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; import { useId } from '../../hooks/useId'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { Caption } from '../Typography/Caption/Caption'; import { Footnote } from '../Typography/Footnote/Footnote'; import styles from './UsersStack.module.css'; @@ -18,7 +20,7 @@ const stylesDirection = { 'column': styles['UsersStack--direction-column'], }; -export interface UsersStackProps extends React.HTMLAttributes { +export interface UsersStackProps extends HTMLAttributesWithRootRef { /** * Массив ссылок на фотографии */ @@ -131,7 +133,6 @@ export const UsersStack = ({ size = 'm', layout, children, - className, direction: directionProp = 'row', ...restProps }: UsersStackProps) => { @@ -190,14 +191,13 @@ export const UsersStack = ({ const direction = (layout && (layout === 'vertical' ? 'column' : 'row')) || directionProp; return ( -
{(photosElements.length > 0 || othersElement) && ( @@ -209,6 +209,6 @@ export const UsersStack = ({ {hasReactNode(children) && ( {children} )} -
+ ); }; diff --git a/packages/vkui/src/components/View/View.tsx b/packages/vkui/src/components/View/View.tsx index 9bfd445bc2..30fc147b00 100644 --- a/packages/vkui/src/components/View/View.tsx +++ b/packages/vkui/src/components/View/View.tsx @@ -10,6 +10,7 @@ import { Platform } from '../../lib/platform'; import { animationEvent } from '../../lib/supportEvents'; import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect'; import { warnOnce } from '../../lib/warnOnce'; +import { HTMLAttributesWithRootRef } from '../../types'; import { useScroll } from '../AppRoot/ScrollContext'; import { useConfigProvider } from '../ConfigProvider/ConfigProviderContext'; import { NavTransitionProvider } from '../NavTransitionContext/NavTransitionContext'; @@ -36,7 +37,7 @@ interface ViewsScrolls { export let scrollsCache: ViewsScrolls = {}; -export interface ViewProps extends React.HTMLAttributes, NavIdProps { +export interface ViewProps extends HTMLAttributesWithRootRef, NavIdProps { activePanel: string; onTransition?(params: { isBack: boolean; from: string; to: string }): void; /** diff --git a/packages/vkui/src/components/View/ViewInfinite.tsx b/packages/vkui/src/components/View/ViewInfinite.tsx index 6e793a0bd2..7403d2d44f 100644 --- a/packages/vkui/src/components/View/ViewInfinite.tsx +++ b/packages/vkui/src/components/View/ViewInfinite.tsx @@ -7,7 +7,7 @@ import { getNavId, NavIdProps } from '../../lib/getNavId'; import { Platform } from '../../lib/platform'; import { animationEvent, transitionEvent } from '../../lib/supportEvents'; import { warnOnce } from '../../lib/warnOnce'; -import { HasPlatform } from '../../types'; +import { HasPlatform, HTMLAttributesWithRootRef } from '../../types'; import { ScrollContext, ScrollContextInterface } from '../AppRoot/ScrollContext'; import { ConfigProviderContext, @@ -42,7 +42,7 @@ export let scrollsCache: ViewsScrolls = {}; export type TransitionParams = { from: string | null; to: string | null }; export interface ViewInfiniteProps - extends React.HTMLAttributes, + extends HTMLAttributesWithRootRef, HasPlatform, NavIdProps { activePanel: string; diff --git a/packages/vkui/src/components/VisuallyHidden/VisuallyHidden.tsx b/packages/vkui/src/components/VisuallyHidden/VisuallyHidden.tsx index 00c1a421e0..e106f50fcf 100644 --- a/packages/vkui/src/components/VisuallyHidden/VisuallyHidden.tsx +++ b/packages/vkui/src/components/VisuallyHidden/VisuallyHidden.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { classNames } from '@vkontakte/vkjs'; import { HasComponent, HasRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import styles from './VisuallyHidden.module.css'; interface VisuallyHiddenProps @@ -15,17 +15,6 @@ interface VisuallyHiddenProps * @since v5.4.0 * @see https://vkcom.github.io/VKUI/#/VisuallyHidden */ -export const VisuallyHidden = ({ - Component = 'span', - getRootRef, - className, - ...restProps -}: VisuallyHiddenProps) => { - return ( - - ); -}; +export const VisuallyHidden = ({ Component = 'span', ...restProps }: VisuallyHiddenProps) => ( + +); diff --git a/packages/vkui/src/testing/utils.tsx b/packages/vkui/src/testing/utils.tsx index 66eb977e3b..098f8e1992 100644 --- a/packages/vkui/src/testing/utils.tsx +++ b/packages/vkui/src/testing/utils.tsx @@ -50,6 +50,7 @@ export type ComponentTestOptions = { style?: boolean; adaptivity?: AdaptivityProps; a11y?: boolean; + getRootRef?: boolean; }; type BasicProps = { style?: any; className?: string }; @@ -75,6 +76,25 @@ export function a11yTest(Component: React.ComponentType) { }); } +export function getRootRefTest(Component: React.ComponentType) { + it('getRootRef', () => { + const stableRef = { current: undefined }; + + const ref = { + get current() { + return stableRef.current; + }, + set current(el) { + stableRef.current = el; + }, + }; + + render(); + + expect(ref.current).not.toBeNull(); + }); +} + export function baselineComponent( RawComponent: React.ComponentType, { @@ -83,6 +103,7 @@ export function baselineComponent( className = true, domAttr = true, a11y = true, + getRootRef = true, adaptivity, }: ComponentTestOptions = {}, ) { @@ -125,6 +146,8 @@ export function baselineComponent( ); } }); + + getRootRef && getRootRefTest(Component); } type RectOptions = { x?: number; y?: number; w?: number; h?: number }; diff --git a/packages/vkui/src/types.ts b/packages/vkui/src/types.ts index 0e8b2087bd..9c798be1ee 100644 --- a/packages/vkui/src/types.ts +++ b/packages/vkui/src/types.ts @@ -87,3 +87,5 @@ interface Nothing {} * @see {@link https://github.com/microsoft/TypeScript/issues/29729} */ export type LiteralUnion = Union | (Type & Nothing); + +export type HTMLAttributesWithRootRef = React.HTMLAttributes & HasRootRef;