Skip to content
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

Feat(web-react): Additional parameter for styleProps and Box refactor #1831

Merged
merged 2 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/web-react/src/components/Box/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import classNames from 'classnames';
import React, { ElementType } from 'react';
import { BorderStyles } from '../../constants';
import { BorderStyles, PaddingStyleProps } from '../../constants';
import { useStyleProps } from '../../hooks';
import { SpiritBoxProps } from '../../types';
import { useBoxStyleProps } from './useBoxStyleProps';
Expand All @@ -17,7 +17,7 @@ const Box = <T extends ElementType = 'div'>(props: SpiritBoxProps<T>) => {
const { elementType: ElementTag = 'div', children, ...restProps } = propsWithDefaults;

const { classProps, props: modifiedProps } = useBoxStyleProps(restProps);
const { styleProps, props: otherProps } = useStyleProps(modifiedProps);
const { styleProps, props: otherProps } = useStyleProps(modifiedProps, PaddingStyleProps);

return (
<ElementTag {...otherProps} {...styleProps} className={classNames(classProps, styleProps.className)}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,78 +19,6 @@ describe('useBoxStyleProps', () => {
expect(result.current.classProps).toBe('bg-secondary');
});

it('should return padding classProps', () => {
const props: SpiritBoxProps = {
padding: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('p-400');
});

it('should return paddingX classProps', () => {
const props: SpiritBoxProps = {
paddingX: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('px-400');
});

it('should return paddingY classProps', () => {
const props: SpiritBoxProps = {
paddingY: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('py-400');
});

it('should return paddingTop classProps', () => {
const props: SpiritBoxProps = {
paddingTop: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('pt-400');
});

it('should return paddingBottom classProps', () => {
const props: SpiritBoxProps = {
paddingBottom: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('pb-400');
});

it('should return paddingLeft classProps', () => {
const props: SpiritBoxProps = {
paddingLeft: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('pl-400');
});

it('should return paddingRight classProps', () => {
const props: SpiritBoxProps = {
paddingRight: 'space-400',
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('pr-400');
});

it('should return responsive padding classProps', () => {
const props: SpiritBoxProps = {
padding: { mobile: 'space-400', tablet: 'space-500', desktop: 'space-600' },
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('p-400 p-tablet-500 p-desktop-600');
});

it('should return border radius classProps', () => {
const props: SpiritBoxProps = {
borderRadius: '200',
Expand All @@ -99,7 +27,7 @@ describe('useBoxStyleProps', () => {
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('border-basic rounded-200 border-100 border-solid');
expect(result.current.classProps).toBe('border-basic rounded-200 border-solid border-100');
});

it('should not return border radius classProps if border with is not set', () => {
Expand All @@ -119,7 +47,7 @@ describe('useBoxStyleProps', () => {
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('border-basic border-100 border-solid');
expect(result.current.classProps).toBe('border-basic border-solid border-100');
});

it('should return border style classProps', () => {
Expand All @@ -129,6 +57,6 @@ describe('useBoxStyleProps', () => {
};
const { result } = renderHook(() => useBoxStyleProps(props));

expect(result.current.classProps).toBe('border-basic border-100 border-dashed');
expect(result.current.classProps).toBe('border-basic border-dashed border-100');
});
});
56 changes: 3 additions & 53 deletions packages/web-react/src/components/Box/useBoxStyleProps.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import classNames from 'classnames';
import { ElementType } from 'react';
import { BorderColors } from '../../constants';
import { BreakpointToken, SpaceToken, SpiritBoxProps } from '../../types';
import { SpiritBoxProps } from '../../types';

export interface UseBoxStyleProps<T> {
/** className props */
Expand All @@ -10,43 +10,10 @@ export interface UseBoxStyleProps<T> {
props: T;
}

export const generateResponsiveUtilityClasses = (
prefix: string,
propValue: SpaceToken | Partial<Record<BreakpointToken, SpaceToken>> | undefined,
): string[] => {
if (propValue && typeof propValue === 'object') {
return Object.entries(propValue).map(([breakpoint, value]) => {
const classValue = value?.replace('space-', '');

return breakpoint === 'mobile' ? `${prefix}-${classValue}` : `${prefix}-${breakpoint}-${classValue}`;
});
}

if (propValue && typeof propValue !== 'object') {
return [`${prefix}-${propValue.replace('space-', '')}`];
}

return [];
};

export const useBoxStyleProps = (
props: Partial<SpiritBoxProps<ElementType>>,
): UseBoxStyleProps<Partial<SpiritBoxProps<ElementType>>> => {
const {
backgroundColor,
borderColor,
borderRadius,
borderStyle,
borderWidth,
padding,
paddingBottom,
paddingLeft,
paddingRight,
paddingTop,
paddingX,
paddingY,
...restProps
} = props || {};
const { backgroundColor, borderColor, borderRadius, borderStyle, borderWidth, ...restProps } = props || {};
const boxBackgroundColor = backgroundColor ? `bg-${backgroundColor}` : '';
let boxBorderColor = borderColor ? borderColor.replace('', 'border-') : '';
let boxBorderRadius = '';
Expand All @@ -61,24 +28,7 @@ export const useBoxStyleProps = (
}
}

const paddingClasses = [
...generateResponsiveUtilityClasses('p', padding),
...generateResponsiveUtilityClasses('pb', paddingBottom),
...generateResponsiveUtilityClasses('pl', paddingLeft),
...generateResponsiveUtilityClasses('pr', paddingRight),
...generateResponsiveUtilityClasses('pt', paddingTop),
...generateResponsiveUtilityClasses('px', paddingX),
...generateResponsiveUtilityClasses('py', paddingY),
];

const boxClasses = classNames(
boxBackgroundColor,
boxBorderColor,
boxBorderRadius,
boxBorderWidth,
boxBorderStyle,
...paddingClasses,
);
const boxClasses = classNames(boxBackgroundColor, boxBorderColor, boxBorderRadius, boxBorderStyle, boxBorderWidth);

return {
classProps: boxClasses,
Expand Down
13 changes: 8 additions & 5 deletions packages/web-react/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import classNames from 'classnames';
import React from 'react';
import { BackgroundColors } from '../../constants';
import { BackgroundColors, PaddingStyleProps } from '../../constants';
import { useStyleProps } from '../../hooks';
import { SpiritFooterProps } from '../../types';
import { PADDING_BOTTOM, PADDING_TOP } from './constants';
Expand All @@ -16,12 +16,15 @@ const defaultStyleProps: Partial<SpiritFooterProps> = {

const Footer = (props: SpiritFooterProps) => {
const propsWithDefaults = { ...defaultStyleProps, ...props };
const { children, backgroundColor, paddingBottom, paddingTop, ...restProps } = propsWithDefaults;
const { classProps } = useFooterStyleProps({ backgroundColor, paddingBottom, paddingTop });
const { styleProps, props: otherProps } = useStyleProps(restProps);
const { children, backgroundColor, ...restProps } = propsWithDefaults;
const { classProps } = useFooterStyleProps({ backgroundColor });
const { styleProps, props: otherProps } = useStyleProps(restProps, {
paddingBottom: PaddingStyleProps.paddingBottom,
paddingTop: PaddingStyleProps.paddingTop,
});
curdaj marked this conversation as resolved.
Show resolved Hide resolved

return (
<footer {...styleProps} {...otherProps} className={classNames(classProps, styleProps.className)}>
<footer {...otherProps} {...styleProps} className={classNames(classProps, styleProps.className)}>
{children}
</footer>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { renderHook } from '@testing-library/react';
import { SpiritFooterProps } from '../../../types';
import { useFooterStyleProps } from '../useFooterStyleProps';

describe('useFooterStyleProps', () => {
it('should return defaults', () => {
const props: SpiritFooterProps = {};
const { result } = renderHook(() => useFooterStyleProps(props));

expect(result.current.classProps).toBe('');
});

it('should return background classProps', () => {
const props: SpiritFooterProps = {
backgroundColor: 'secondary',
};
const { result } = renderHook(() => useFooterStyleProps(props));

expect(result.current.classProps).toBe('bg-secondary');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@ export interface UseFooterStyleProps {
}

export function useFooterStyleProps(props: Partial<SpiritFooterProps>): UseFooterStyleProps {
const { backgroundColor, paddingBottom, paddingTop } = props;

const { backgroundColor } = props;
const footerBackgroundColor = backgroundColor ? `bg-${backgroundColor}` : '';
const footerPaddingBottom = paddingBottom ? paddingBottom.replace('space-', 'pb-') : '';
const footerPaddingTop = paddingTop ? paddingTop.replace('space-', 'pt-') : '';

const classProps = classNames({
[footerBackgroundColor]: backgroundColor,
[footerPaddingBottom]: paddingBottom,
[footerPaddingTop]: paddingTop,
});

return {
Expand Down
10 changes: 10 additions & 0 deletions packages/web-react/src/constants/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ export const SpacingStyleProp = {
marginX: 'mx',
marginY: 'my',
} as const;

export const PaddingStyleProps = {
padding: 'p',
paddingBottom: 'pb',
paddingLeft: 'pl',
paddingRight: 'pr',
paddingTop: 'pt',
paddingX: 'px',
paddingY: 'py',
} as const;
42 changes: 42 additions & 0 deletions packages/web-react/src/hooks/__tests__/styleProps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,46 @@ describe('styleProps', () => {
expect(result.current.styleProps).toEqual(expected);
});
});

it('should process style props with additional utilities', () => {
const mockProps = {
margin: 'space-100',
marginX: 'space-200',
marginY: 'space-400',
padding: 'space-500',
paddingX: 'space-600',
paddingY: 'space-700',
};
const additionalUtilities = {
padding: 'p',
paddingX: 'px',
paddingY: 'py',
};

const { result } = renderHook(() => useStyleProps(mockProps as StyleProps, additionalUtilities));

expect(result.current.styleProps).toEqual({
className: 'm-100 mx-200 my-400 p-500 px-600 py-700',
style: undefined,
});
});

it('should process style props with responsive additional utilities', () => {
const mockProps = {
margin: 'space-100',
marginX: 'space-200',
marginY: 'space-400',
padding: { mobile: 'space-500', tablet: 'space-600', desktop: 'space-700' },
};
const additionalUtilities = {
padding: 'p',
};

const { result } = renderHook(() => useStyleProps(mockProps as StyleProps, additionalUtilities));

expect(result.current.styleProps).toEqual({
className: 'm-100 mx-200 my-400 p-500 p-tablet-600 p-desktop-700',
style: undefined,
});
});
});
Loading
Loading