-
Notifications
You must be signed in to change notification settings - Fork 203
feat(PanelHeader,PanelHeaderContext): remove FixedLayout using #9765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
5547445
24f52cb
84be8fb
5cb9448
8049d14
cc7ba10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| 'use client'; | ||
|
|
||
| import * as React from 'react'; | ||
| import { classNames } from '@vkontakte/vkjs'; | ||
| import { resolveLayoutProps } from '../../lib/layouts'; | ||
| import type { LayoutProps } from '../../lib/layouts/types'; | ||
|
|
@@ -12,7 +15,45 @@ const displayClassNames = { | |
| 'contents': styles.displayContents, | ||
| }; | ||
|
|
||
| export interface BoxProps extends RootComponentProps<HTMLElement>, LayoutProps { | ||
| type BoxComponent = RootComponentProps<HTMLElement>['Component'] | React.ElementType[]; | ||
|
|
||
| function composeComponents( | ||
| component: BoxComponent | undefined, | ||
| ): RootComponentProps<HTMLElement>['Component'] { | ||
| if (!Array.isArray(component)) { | ||
| return component; | ||
| } | ||
|
|
||
| if (component.length === 0) { | ||
| return undefined; | ||
| } | ||
|
|
||
| return component.reduceRight<React.ElementType>( | ||
| (InnerComponent, WrapperComponent) => | ||
| // eslint-disable-next-line react/display-name -- динамическая композиция обёрток | ||
| React.forwardRef<HTMLElement, RootComponentProps<HTMLElement>>((props, ref) => ( | ||
| <WrapperComponent {...props} ref={ref} Component={InnerComponent} /> | ||
| )), | ||
| 'div', | ||
| ); | ||
| } | ||
|
|
||
| export interface BoxProps extends Omit<RootComponentProps<HTMLElement>, 'Component'>, LayoutProps { | ||
| /** | ||
| * Компонент для рендера или массив компонентов для композиции. | ||
| * | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пустой комментарий |
||
| * Можно передать один компонент или массив компонентов. При передаче массива | ||
| * компоненты будут вложены друг в друга справа налево, начиная с `div`. | ||
| * | ||
| * @example | ||
| * // Один компонент | ||
| * <Box Component="section" /> | ||
| * | ||
| * @example | ||
| * // Массив компонентов — рендер: Wrapper → Link → div | ||
| * <Box Component={[Wrapper, Link]} /> | ||
| */ | ||
| Component?: BoxComponent | undefined; | ||
| /** | ||
| * Возможность задать css-свойство `display`. | ||
| */ | ||
|
|
@@ -24,12 +65,21 @@ export interface BoxProps extends RootComponentProps<HTMLElement>, LayoutProps { | |
| * | ||
| * @since 7.9.0 | ||
| */ | ||
| export const Box = ({ className, style, display, ...restProps }: BoxProps) => { | ||
| export const Box = ({ | ||
| className, | ||
| style, | ||
| display, | ||
| Component: ComponentProp, | ||
| ...restProps | ||
| }: BoxProps) => { | ||
| const resolvedProps = resolveLayoutProps(restProps); | ||
|
|
||
| const Component = React.useMemo(() => composeComponents(ComponentProp), [ComponentProp]); | ||
|
|
||
| return ( | ||
| <RootComponent | ||
| {...resolvedProps} | ||
| Component={Component} | ||
| baseClassName={resolvedProps.className} | ||
| baseStyle={resolvedProps.style} | ||
| className={classNames(className, display && displayClassNames[display])} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| 'use client'; | ||
|
|
||
| import * as React from 'react'; | ||
| import { usePlatform } from '../../hooks/usePlatform'; | ||
| import { useResizeObserver } from '../../hooks/useResizeObserver'; | ||
| import { defineComponentDisplayNames } from '../../lib/react/defineComponentDisplayNames'; | ||
| import type { HasComponent } from '../../types'; | ||
| import { SplitColContext } from '../SplitCol/SplitColContext'; | ||
|
|
||
| type SplitColWidthWrapperProps = React.HTMLAttributes<HTMLElement> & HasComponent; | ||
|
|
||
| export const SplitColWidthWrapper: React.ForwardRefExoticComponent< | ||
| React.PropsWithoutRef<SplitColWidthWrapperProps> & React.RefAttributes<HTMLElement> | ||
| // eslint-disable-next-line react/display-name -- используется defineComponentDisplayNames | ||
| > = React.forwardRef<HTMLElement, SplitColWidthWrapperProps>( | ||
| ({ Component = 'div', style, ...restProps }, forwardedRef) => { | ||
| const platform = usePlatform(); | ||
| const { colRef } = React.useContext(SplitColContext); | ||
| const [width, setWidth] = React.useState<string | undefined>(undefined); | ||
|
|
||
| const doResize = React.useCallback(() => { | ||
| if (!colRef?.current) { | ||
| setWidth(undefined); | ||
| return; | ||
| } | ||
|
|
||
| const computedStyle = getComputedStyle(colRef.current); | ||
|
|
||
| setWidth( | ||
| `${ | ||
| colRef.current.clientWidth - | ||
| parseFloat(computedStyle.paddingLeft || '0') - | ||
| parseFloat(computedStyle.paddingRight || '0') | ||
| }px`, | ||
| ); | ||
| }, [colRef]); | ||
|
|
||
| React.useEffect(doResize, [doResize, platform]); | ||
| useResizeObserver(colRef, doResize); | ||
|
|
||
| return <Component {...restProps} ref={forwardedRef} style={{ width, ...style }} />; | ||
| }, | ||
| ); | ||
|
|
||
| if (process.env.NODE_ENV !== 'production') { | ||
| defineComponentDisplayNames(SplitColWidthWrapper, 'SplitColWidthWrapper'); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| 'use client'; | ||
|
|
||
| import * as React from 'react'; | ||
| import { defineComponentDisplayNames } from '../../lib/react/defineComponentDisplayNames'; | ||
| import type { HasComponent } from '../../types'; | ||
| import { OnboardingTooltipContainer } from './OnboardingTooltipContainer'; | ||
|
|
||
| type OnboardingTooltipFixedContainerProps = React.HTMLAttributes<HTMLDivElement> & HasComponent; | ||
|
|
||
| export const OnboardingTooltipFixedContainer: React.ForwardRefExoticComponent< | ||
| React.PropsWithoutRef<OnboardingTooltipFixedContainerProps> & React.RefAttributes<HTMLDivElement> | ||
| // eslint-disable-next-line react/display-name -- используется defineComponentDisplayNames | ||
| > = React.forwardRef<HTMLDivElement, OnboardingTooltipFixedContainerProps>((props, ref) => ( | ||
| <OnboardingTooltipContainer {...props} fixed ref={ref} /> | ||
| )); | ||
|
|
||
| if (process.env.NODE_ENV !== 'production') { | ||
| defineComponentDisplayNames(OnboardingTooltipFixedContainer, 'OnboardingTooltipFixedContainer'); | ||
| } |
|
SevereCloud marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,9 @@ import { type SizeTypeValues, ViewWidth, type ViewWidthType } from '../../lib/ad | |
| import { useCSSKeyframesAnimationController } from '../../lib/animation'; | ||
| import type { HTMLAttributesWithRootRef } from '../../types'; | ||
| import { useScrollLock } from '../AppRoot/ScrollContext'; | ||
| import { FixedLayout } from '../FixedLayout/FixedLayout'; | ||
| import { Box } from '../Box/Box'; | ||
| import { SplitColWidthWrapper } from '../FixedLayout/SplitColWidthWrapper'; | ||
| import { OnboardingTooltipFixedContainer } from '../OnboardingTooltip/OnboardingTooltipFixedContainer'; | ||
| import styles from './PanelHeaderContext.module.css'; | ||
|
|
||
| function getViewWidthClassName( | ||
|
|
@@ -43,6 +45,8 @@ export interface PanelHeaderContextProps extends HTMLAttributesWithRootRef<HTMLD | |
| onClose: VoidFunction; | ||
| } | ||
|
|
||
| const ComponentDecorators = [SplitColWidthWrapper, OnboardingTooltipFixedContainer]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Есть кейсы когда для
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Сложно сказать. Я в целом не особо вижу смысл в компоненте |
||
|
|
||
| /** | ||
| * @see https://vkui.io/components/panel-header-context | ||
| */ | ||
|
|
@@ -82,16 +86,19 @@ export const PanelHeaderContext = ({ | |
| } | ||
|
|
||
| return ( | ||
| <FixedLayout | ||
| {...restProps} | ||
| <Box | ||
| Component={ComponentDecorators} | ||
| className={classNames( | ||
| styles.host, | ||
| platform === 'ios' && styles.ios, | ||
| opened ? styles.opened : styles.closing, | ||
| getViewWidthClassName(viewWidth, legacySizeX), | ||
| className, | ||
| )} | ||
| vertical="top" | ||
| position="fixed" | ||
| inlineSize="100%" | ||
| insetBlockStart={0} | ||
| {...restProps} | ||
| > | ||
| <div | ||
| onClick={(event) => { | ||
|
|
@@ -108,6 +115,6 @@ export const PanelHeaderContext = ({ | |
| > | ||
| <div className={styles.content}>{children}</div> | ||
| </div> | ||
| </FixedLayout> | ||
| </Box> | ||
| ); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Кажется слишком мощная затея + пересекается #9918