Skip to content

Commit

Permalink
feat(Spacing): add css variables support (#7955)
Browse files Browse the repository at this point in the history
* feat(Spacing): add css variables support

* fix: review fixes

* fix nit
  • Loading branch information
BlackySoul authored Nov 21, 2024
1 parent d35dac3 commit 74a656b
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ComponentPlayground, type ComponentPlaygroundProps } from '@vkui-e2e/playground-helpers';
import { type SpacingSize, spacingSizeClassNames } from '../../lib/spacings/sizes';
import { type CSSCustomProperties } from '../../types';
import { Separator, type SeparatorProps } from './Separator';

const sizes = Object.keys(spacingSizeClassNames) as SpacingSize[];
const divStyle: CSSCustomProperties = {
'--my-custom-var': '20px',
};

export const SeparatorPlayground = (props: ComponentPlaygroundProps) => {
return (
Expand Down Expand Up @@ -33,10 +37,14 @@ export const SeparatorPlayground = (props: ComponentPlaygroundProps) => {
align: ['start', 'center', 'end'],
size: ['3xl'],
},
{
direction: ['horizontal', 'vertical'],
size: ['--my-custom-var'],
},
]}
>
{(props: SeparatorProps) => (
<div style={props.direction === 'vertical' ? { display: 'flex' } : undefined}>
<div style={props.direction === 'vertical' ? { display: 'flex', ...divStyle } : divStyle}>
First Item
<Separator {...props} />
Second Item
Expand Down
52 changes: 32 additions & 20 deletions packages/vkui/src/components/Separator/Separator.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { classNames } from '@vkontakte/vkjs';
import { spacingSizeClassNames, type SpacingSizeProp } from '../../lib/spacings/sizes';
import { resolveSpacingSize, type SpacingSizeProp } from '../../lib/spacings/sizes';
import type { HTMLAttributesWithRootRef } from '../../types';
import { RootComponent } from '../RootComponent/RootComponent';
import styles from './Separator.module.css';
Expand All @@ -21,6 +21,8 @@ export interface SeparatorProps extends HTMLAttributesWithRootRef<HTMLDivElement
direction?: 'horizontal' | 'vertical';
/**
* Размер контейнера, в который вложен разделитель
*
* Принимает значения дизайн-системы, числовые значения и css-переменные
*/
size?: SpacingSizeProp;
/**
Expand Down Expand Up @@ -56,22 +58,32 @@ export const Separator = ({
style,
size,
...restProps
}: SeparatorProps): React.ReactNode => (
<RootComponent
{...restProps}
baseClassName={classNames(
padding && styles.padded,
appearanceClassNames[appearance],
typeof size === 'string' && spacingSizeClassNames[size],
directionClassNames[direction],
size !== undefined && styles.sized,
align !== 'center' && alignClassNames[align],
)}
style={{
...(typeof size === 'number' && { [CUSTOM_CSS_TOKEN_FOR_USER_SIZE]: `${size}px` }),
...style,
}}
>
<hr className={styles.in} />
</RootComponent>
);
}: SeparatorProps): React.ReactNode => {
const [spacingSizeClassName, spacingSizeStyle] = resolveSpacingSize(
CUSTOM_CSS_TOKEN_FOR_USER_SIZE,
size,
);
return (
<RootComponent
{...restProps}
baseClassName={classNames(
padding && styles.padded,
appearanceClassNames[appearance],
directionClassNames[direction],
size !== undefined && styles.sized,
align !== 'center' && alignClassNames[align],
spacingSizeClassName,
)}
style={
spacingSizeStyle
? {
...spacingSizeStyle,
...style,
}
: style
}
>
<hr className={styles.in} />
</RootComponent>
);
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { ComponentPlayground, type ComponentPlaygroundProps } from '@vkui-e2e/playground-helpers';
import { type SpacingSize, spacingSizeClassNames } from '../../lib/spacings/sizes';
import { type CSSCustomProperties } from '../../types';
import { Div } from '../Div/Div';
import { Separator } from '../Separator/Separator';
import { Spacing, type SpacingProps } from './Spacing';

const sizes = Object.keys(spacingSizeClassNames) as SpacingSize[];
const divStyle: React.CSSProperties & CSSCustomProperties = {
'width': 100,
'--my-custom-var': '8px',
};

export const SpacingPlayground = (props: ComponentPlaygroundProps) => {
return (
<ComponentPlayground
{...props}
propSets={[
{
size: [undefined, ...sizes, 8, 16, 24],
size: [undefined, ...sizes, 8, 16, 24, '--my-custom-var'],
},
]}
>
{({ size }: SpacingProps) => (
<Div style={{ width: 100 }}>
<Div style={divStyle}>
<Separator padding />
<Spacing size={size} />
<Separator padding />
Expand Down
7 changes: 7 additions & 0 deletions packages/vkui/src/components/Spacing/Spacing.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ describe('Spacing', () => {
expect(h.container.firstElementChild).toHaveStyle(`${CUSTOM_CSS_TOKEN_FOR_USER_GAP}: 16px`);
});

it('should use css variable size', () => {
const h = render(<Spacing size="--my-custom-var" />);
expect(h.container.firstElementChild).toHaveStyle(
`${CUSTOM_CSS_TOKEN_FOR_USER_GAP}: var(--my-custom-var)`,
);
});

it('should preserve user style', () => {
const h = render(<Spacing size={16} style={{ fontSize: 12 }} />);
expect(h.container.firstElementChild).toHaveStyle(
Expand Down
25 changes: 16 additions & 9 deletions packages/vkui/src/components/Spacing/Spacing.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { spacingSizeClassNames, type SpacingSizeProp } from '../../lib/spacings/sizes';
import { resolveSpacingSize, type SpacingSizeProp } from '../../lib/spacings/sizes';
import type { HTMLAttributesWithRootRef } from '../../types';
import { RootComponent } from '../RootComponent/RootComponent';
import styles from './Spacing.module.css';
Expand All @@ -10,6 +10,8 @@ export const CUSTOM_CSS_TOKEN_FOR_USER_GAP = '--vkui_internal--spacing_size';
export interface SpacingProps extends HTMLAttributesWithRootRef<HTMLDivElement> {
/**
* Высота спэйсинга
*
* Принимает значения дизайн-системы, числовые значения и css-переменные
*/
size?: SpacingSizeProp;
/**
Expand All @@ -23,17 +25,22 @@ export interface SpacingProps extends HTMLAttributesWithRootRef<HTMLDivElement>
* @see https://vkcom.github.io/VKUI/#/Spacing
*/
export const Spacing = ({ size = 'm', style, ...restProps }: SpacingProps): React.ReactNode => {
const [spacingSizeClassName, spacingSizeStyle] = resolveSpacingSize(
CUSTOM_CSS_TOKEN_FOR_USER_GAP,
size,
);
return (
<RootComponent
{...restProps}
style={{
...(typeof size === 'number' && { [CUSTOM_CSS_TOKEN_FOR_USER_GAP]: `${size}px` }),
...style,
}}
baseClassName={classNames(
styles.host,
typeof size === 'string' && spacingSizeClassNames[size],
)}
style={
spacingSizeStyle
? {
...spacingSizeStyle,
...style,
}
: style
}
baseClassName={classNames(styles.host, spacingSizeClassName)}
/>
);
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 17 additions & 2 deletions packages/vkui/src/lib/spacings/sizes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { LiteralUnion } from '../../types';
import type { CSSCustomProperties, LiteralUnion } from '../../types';
import styles from '../../styles/spacings.module.css';

export type SpacingSize = '2xs' | 'xs' | 's' | 'm' | 'l' | 'xl' | '2xl' | '3xl' | '4xl';
Expand All @@ -15,4 +15,19 @@ export const spacingSizeClassNames: Record<SpacingSize, string> = {
'4xl': styles['-spacing--4xl'],
};

export type SpacingSizeProp = LiteralUnion<SpacingSize, number>;
export type SpacingSizeProp = LiteralUnion<SpacingSize | `--${string}`, number>;

export function resolveSpacingSize(
cssVariable: string,
size?: SpacingSizeProp,
): [string | undefined, CSSCustomProperties | undefined] {
if (typeof size === 'string') {
if (size.startsWith('--')) {
return [undefined, { [cssVariable]: `var(${size})` }];
} else {
return [spacingSizeClassNames[size as SpacingSize], undefined];
}
}

return [undefined, typeof size === 'number' ? { [cssVariable]: `${size}px` } : undefined];
}

0 comments on commit 74a656b

Please sign in to comment.