Skip to content

Commit

Permalink
refactor: add mergeStyle (#7979)
Browse files Browse the repository at this point in the history
* refactor: add mergeStyle

* fix: check objects.length <= 1

* fix: mini
  • Loading branch information
SevereCloud authored Nov 22, 2024
1 parent 99acad5 commit db19559
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 32 deletions.
3 changes: 2 additions & 1 deletion packages/vkui/src/components/AspectRatio/AspectRatio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ export function AspectRatio({
}: AspectRatioProps): JSX.Element {
const style: React.CSSProperties & CSSCustomProperties = {
'--vkui_internal--aspect_ratio': String(ratio),
...styleProp,
};

return (
<RootComponent
baseClassName={classNames(styles.host, mode === 'stretch' && styles.modeStretch)}
style={{ ...styleProp, ...style }}
style={style}
{...props}
/>
);
Expand Down
3 changes: 2 additions & 1 deletion packages/vkui/src/components/Flex/Flex.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Children } from 'react';
import { classNames } from '@vkontakte/vkjs';
import { mergeStyle } from '../../helpers/mergeStyle';
import {
calculateGap,
columnGapClassNames,
Expand Down Expand Up @@ -104,7 +105,7 @@ export const Flex: React.FC<FlexProps> & {
withGaps && styles.withGaps,
withGaps && getGapsPresets(rowGap, columnGap),
)}
style={withGaps ? { ...getGapsByUser(rowGap, columnGap), ...styleProp } : styleProp}
style={mergeStyle(getGapsByUser(rowGap, columnGap), styleProp)}
>
{children}
</RootComponent>
Expand Down
18 changes: 13 additions & 5 deletions packages/vkui/src/components/HorizontalCell/HorizontalCell.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import * as React from 'react';
import { classNames, hasReactNode } from '@vkontakte/vkjs';
import type { HasRef, HasRootRef, HTMLAttributesWithRootRef, LiteralUnion } from '../../types';
import { mergeStyle } from '../../helpers/mergeStyle';
import type {
CSSCustomProperties,
HasRef,
HasRootRef,
HTMLAttributesWithRootRef,
LiteralUnion,
} from '../../types';
import { Avatar } from '../Avatar/Avatar';
import { Tappable, type TappableProps } from '../Tappable/Tappable';
import { Caption } from '../Typography/Caption/Caption';
Expand Down Expand Up @@ -75,13 +82,14 @@ export const HorizontalCell = ({
}: HorizontalCellProps): React.ReactNode => {
const hasTypography =
hasReactNode(title) || hasReactNode(subtitle) || hasReactNode(extraSubtitle);

const customProperties: CSSCustomProperties | undefined =
typeof size === 'number' ? { [CUSTOM_CSS_TOKEN_FOR_CELL_WIDTH]: `${size}px` } : undefined;

return (
<div
ref={getRootRef}
style={{
...(typeof size === 'number' && { [CUSTOM_CSS_TOKEN_FOR_CELL_WIDTH]: `${size}px` }),
...style,
}}
style={mergeStyle(customProperties, style)}
className={classNames(
styles.host,
typeof size === 'string' && stylesSize[size],
Expand Down
6 changes: 4 additions & 2 deletions packages/vkui/src/components/Image/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { mergeStyle } from '../../helpers/mergeStyle';
import { type CSSCustomProperties } from '../../types';
import { ImageBase, type ImageBaseOverlayProps, type ImageBaseProps } from '../ImageBase/ImageBase';
import { ImageBadge, type ImageBadgeProps } from './ImageBadge/ImageBadge';
import styles from './Image.module.css';
Expand Down Expand Up @@ -118,7 +120,7 @@ export const Image: React.FC<ImageProps> & {
objectFit = 'cover',
...restProps
}: ImageProps) => {
const borderStyles = React.useMemo(
const borderStyles: CSSCustomProperties<string | undefined> = React.useMemo(
() => ({
'--vkui_internal--Image_border_radius': getBorderRadiusBySizeInPx(size, borderRadius),
'--vkui_internal--Image_border_start_start_radius': getBorderRadiusBySizeInPx(
Expand Down Expand Up @@ -153,7 +155,7 @@ export const Image: React.FC<ImageProps> & {
{...restProps}
objectFit={objectFit}
size={size}
style={{ ...borderStyles, ...style }}
style={mergeStyle(borderStyles, style)}
className={classNames(
className,
styles.host,
Expand Down
9 changes: 5 additions & 4 deletions packages/vkui/src/components/Popper/Popper.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import * as React from 'react';
import { mergeStyle } from '../../helpers/mergeStyle';
import { useExternRef } from '../../hooks/useExternRef';
import {
autoUpdateFloatingElement,
Expand Down Expand Up @@ -165,16 +166,16 @@ export const Popper = ({
{...restProps}
baseClassName={styles.host}
getRootRef={handleRootRef}
style={{
...convertFloatingDataToReactCSSProperties(
style={mergeStyle(
convertFloatingDataToReactCSSProperties(
floatingPositionStrategy,
floatingDataX,
floatingDataY,
sameWidth ? null : undefined,
middlewareData,
),
...styleProp,
}}
styleProp,
)}
>
{arrow && (
<FloatingArrow
Expand Down
3 changes: 2 additions & 1 deletion packages/vkui/src/components/Progress/Progress.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { clamp } from '../../helpers/math';
import { mergeStyle } from '../../helpers/mergeStyle';
import type { HTMLAttributesWithRootRef } from '../../types';
import { RootComponent } from '../RootComponent/RootComponent';
import styles from './Progress.module.css';
Expand Down Expand Up @@ -53,7 +54,7 @@ export const Progress = ({
<RootComponent
aria-valuenow={value}
title={title}
style={{ ...styleHeight, ...style }}
style={mergeStyle(styleHeight, style)}
{...restProps}
role="progressbar"
aria-valuemin={PROGRESS_MIN_VALUE}
Expand Down
10 changes: 2 additions & 8 deletions packages/vkui/src/components/Separator/Separator.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { classNames } from '@vkontakte/vkjs';
import { mergeStyle } from '../../helpers/mergeStyle';
import { resolveSpacingSize, type SpacingSizeProp } from '../../lib/spacings/sizes';
import type { HTMLAttributesWithRootRef } from '../../types';
import { RootComponent } from '../RootComponent/RootComponent';
Expand Down Expand Up @@ -74,14 +75,7 @@ export const Separator = ({
align !== 'center' && alignClassNames[align],
spacingSizeClassName,
)}
style={
spacingSizeStyle
? {
...spacingSizeStyle,
...style,
}
: style
}
style={mergeStyle(spacingSizeStyle, style)}
>
<hr className={styles.in} />
</RootComponent>
Expand Down
3 changes: 2 additions & 1 deletion packages/vkui/src/components/SimpleGrid/SimpleGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { classNames } from '@vkontakte/vkjs';
import { mergeStyle } from '../../helpers/mergeStyle';
import {
calculateGap,
columnGapClassNames,
Expand Down Expand Up @@ -86,7 +87,7 @@ export const SimpleGrid = ({
typeof columnGap === 'string' && columnGapClassNames[columnGap],
typeof rowGap === 'string' && rowGapClassNames[rowGap],
)}
style={{ ...style, ...styleProp }}
style={mergeStyle(style, styleProp)}
/>
);
};
3 changes: 2 additions & 1 deletion packages/vkui/src/components/Skeleton/Skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { millisecondsInSecond } from 'date-fns/constants';
import { mergeStyle } from '../../helpers/mergeStyle';
import { useExternRef } from '../../hooks/useExternRef';
import { useGlobalEventListener } from '../../hooks/useGlobalEventListener';
import { useStateWithPrev } from '../../hooks/useStateWithPrev';
Expand Down Expand Up @@ -183,7 +184,7 @@ export const Skeleton = ({
getRootRef={rootRef}
Component="span"
baseClassName={classNames(styles.host, disableAnimation && styles.disableAnimation)}
style={{ ...skeletonStyle, ...style }}
style={mergeStyle(skeletonStyle, style)}
{...restProps}
>
{children || <>&zwnj;</>}
Expand Down
10 changes: 2 additions & 8 deletions packages/vkui/src/components/Spacing/Spacing.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { mergeStyle } from '../../helpers/mergeStyle';
import { resolveSpacingSize, type SpacingSizeProp } from '../../lib/spacings/sizes';
import type { HTMLAttributesWithRootRef } from '../../types';
import { RootComponent } from '../RootComponent/RootComponent';
Expand Down Expand Up @@ -32,14 +33,7 @@ export const Spacing = ({ size = 'm', style, ...restProps }: SpacingProps): Reac
return (
<RootComponent
{...restProps}
style={
spacingSizeStyle
? {
...spacingSizeStyle,
...style,
}
: style
}
style={mergeStyle(spacingSizeStyle, style)}
baseClassName={classNames(styles.host, spacingSizeClassName)}
/>
);
Expand Down
45 changes: 45 additions & 0 deletions packages/vkui/src/helpers/mergeStyle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { mergeStyle } from './mergeStyle';

describe(mergeStyle, () => {
it.each([
{
a: undefined,
b: undefined,
output: undefined,
},
{
a: { color: 'red' },
b: { background: 'blue' },
output: { color: 'red', background: 'blue' },
},
{
a: undefined,
b: { color: 'red' },
output: { color: 'red' },
},
{
a: { color: 'red' },
b: undefined,
output: { color: 'red' },
},
{
a: { color: 'red' },
b: { color: 'blue' },
output: { color: 'blue' },
},
] as const)('mergeStyle($a, $b) is $output', ({ a, b, output }) =>
expect(mergeStyle(a, b)).toStrictEqual(output),
);

const testStyles = { display: 'flex' };
const copyTestStyles = { ...testStyles };

it.each([[[undefined, testStyles]], [[testStyles, undefined]]] as const)(
'mergeStyle(%p) is not copy',
([a, b]) => {
const result = mergeStyle(a, b);
expect(result).toBe(testStyles);
expect(result).not.toBe(copyTestStyles);
},
);
});
15 changes: 15 additions & 0 deletions packages/vkui/src/helpers/mergeStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Мержит стили, пытаясь уменьшить кол-во копирований
*
* ## Пример
*
* ```ts
* const style = mergeStyle(arrowStyles, styleProp)
* ```
*/
export function mergeStyle(
a: React.CSSProperties | undefined,
b: React.CSSProperties | undefined,
): React.CSSProperties | undefined {
return a && b ? { ...a, ...b } : a || b;
}

0 comments on commit db19559

Please sign in to comment.