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

fix(blade): chipgroup grid alignment #2536

Merged
merged 31 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
39da608
chore: expose grid and flexbox props
tewarig Feb 9, 2025
67b9d5f
fix: add changeset
tewarig Feb 9, 2025
fb84e53
chore: update lint error
tewarig Feb 9, 2025
2481620
feat: add width prop in chip
tewarig Feb 10, 2025
1e89e97
feat: let user change the layout
tewarig Feb 10, 2025
72efaeb
chore: remove unsed commit types
tewarig Feb 10, 2025
18838c7
chore: review changes
tewarig Feb 10, 2025
464acc8
chore: update snap
tewarig Feb 10, 2025
f280c95
chore: removed unused utils
tewarig Feb 11, 2025
98296fb
chore: remove types
tewarig Feb 11, 2025
7c9803a
chore: update ts
tewarig Feb 11, 2025
f3633f3
chore: review change
tewarig Feb 11, 2025
a818274
chore: update snap
tewarig Feb 11, 2025
dc6fa5a
chore : review change
tewarig Feb 11, 2025
23ee578
chore: review changes
tewarig Feb 11, 2025
f4652cb
chore: addMaxWidth , minWidth
tewarig Feb 11, 2025
bb40a3f
chore: expose maxWidth , minWidth
tewarig Feb 11, 2025
62f74c1
chore: update chipgroup width
tewarig Feb 11, 2025
2a32ed1
chore: more refactor
tewarig Feb 11, 2025
a1f66f9
chore: update snap
tewarig Feb 11, 2025
c02f1e9
chore: chipgroup custom layout
tewarig Feb 12, 2025
1836fdc
chore: change to getBaseBoxStyles
tewarig Feb 12, 2025
8adc366
chore: refactor width
tewarig Feb 12, 2025
3443de8
chore: refactor
tewarig Feb 12, 2025
1774421
chore: more changes
tewarig Feb 12, 2025
833b335
chore: snap update
tewarig Feb 12, 2025
4be16b6
chore: change to width 100%
tewarig Feb 13, 2025
bf73016
chore: update snaps
tewarig Feb 13, 2025
eee166f
chore: review changes
tewarig Feb 14, 2025
29bfc15
chore: docs update
tewarig Feb 17, 2025
aad91c2
chore: change baseBoxProps to box props
tewarig Feb 17, 2025
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
5 changes: 5 additions & 0 deletions .changeset/two-cows-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@razorpay/blade': patch
---

fix(blade): allow consumers to align chips in chipgroup
Original file line number Diff line number Diff line change
Expand Up @@ -332,5 +332,5 @@ type BoxRefType = Platform.Select<{
native: View;
}>;

export type { BaseBoxProps, BoxProps, BoxRefType, StyledPropsBlade, FlexboxProps };
export type { BaseBoxProps, BoxProps, BoxRefType, StyledPropsBlade, FlexboxProps, GridProps };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

export { validBoxAsValues };
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,5 @@ const getStyledProps = (props: Record<string, any>): StyledPropsBlade => {
return removeUndefinedStyledProps(makeStyledProps(props));
};

export type { StyledPropsBlade };
export type { StyledPropsBlade, StyledPropsInputType };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

export { getStyledProps, makeStyledProps, removeUndefinedStyledProps };
3 changes: 2 additions & 1 deletion packages/blade/src/components/Chip/Chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type OnChange = ({
}) => void;

const _Chip: React.ForwardRefRenderFunction<BladeElementRef, ChipProps> = (
{ isDisabled, value, children, icon: Icon, color, testID, _motionMeta, ...rest },
{ isDisabled, value, children, icon: Icon, color, testID, _motionMeta, width, ...rest },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should expose minWidth, maxWidth as well right if we're exposing width?

ref,
) => {
const { theme } = useTheme();
Expand Down Expand Up @@ -201,6 +201,7 @@ const _Chip: React.ForwardRefRenderFunction<BladeElementRef, ChipProps> = (
}
height={makeSize(chipHeightTokens[_size])}
gap="spacing.3"
width={width}
>
{Icon ? (
<BaseBox display="flex">
Expand Down
77 changes: 77 additions & 0 deletions packages/blade/src/components/Chip/ChipGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -727,3 +727,80 @@ chipRef.parameters = {
exclude: ['icon'],
},
};

export const MultiChipStory: StoryFn<typeof ChipGroupComponent> = () => {
const chipArray = [
{
value: '100',
label: '₹100',
},
{
value: '500',
label: '₹500',
},
{
value: '1000',
label: '₹1000',
},
{
value: '2000',
label: '₹2000',
},
{
value: '5000',
label: '₹5000',
},
{
value: '10000',
label: '₹10000',
},
{
value: '20000',
label: '₹20000',
},
{
value: '50000',
label: '₹50000',
},
{
value: '100000',
label: '₹100000',
},
{
value: '200000',
label: '₹200000',
},
];

return (
<Box gap="spacing.3" display="flex" flexDirection="column">
<ChipGroupComponent
selectionType="single"
label="Select a gift card with value (without custom chipGroupContainerLayout)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
label="Select a gift card with value (without custom chipGroupContainerLayout)"
label="Select a gift card with value (without custom chipGroupContainerLayout)"

what is chipGroupContainerLayout?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • with default layout
  • with custom layout

>
{chipArray.map((chip, index) => (
<ChipComponent key={index} value={chip.value}>
{chip.label}
</ChipComponent>
))}
</ChipGroupComponent>
<ChipGroupComponent
selectionType="single"
label="Select a gift card with value (custom chipGroupContainerLayout)"
>
<Box
display="grid"
gridTemplateColumns="repeat(3, minmax(0,120px))"
gridTemplateRows="repeat(3, minmax(0,30px))"
gap="spacing.3"
>
{chipArray.map((chip, index) => (
<ChipComponent key={index} value={chip.value} width="120px">
Copy link
Member

@anuraghazra anuraghazra Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 We shouldn't need to add explicit pixel values in ChipComponent.

ideally width=100% or flex={1} should work, instead of hard coding 120px like so:

<ChipComponent key={index} value={chip.value} width="100%" />

I would assume this would work and the chip should automatically stretch/flex to available space.

Not to mention explicit pixel values will break the layout if there is no space:

image

{chip.label}
</ChipComponent>
))}
</Box>
</ChipGroupComponent>
</Box>
);
};
29 changes: 27 additions & 2 deletions packages/blade/src/components/Chip/ChipGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { chipGroupGapTokens, chipGroupLabelSizeTokens } from './chipTokens';
import { ChipGroupProvider } from './ChipGroupContext';
import { useChipGroup } from './useChipGroup';
import type { ChipGroupProps } from './types';
import { getLayOutProps } from './utils';
import BaseBox from '~components/Box/BaseBox';
import { FormHint, FormLabel } from '~components/Form';
import { SelectorGroupField } from '~components/Form/Selector/SelectorGroupField';
Expand All @@ -12,6 +13,7 @@ import { Text } from '~components/Typography';
import type { BladeElementRef } from '~utils/types';
import { throwBladeError } from '~utils/logger';
import { makeAnalyticsAttribute } from '~utils/makeAnalyticsAttribute';
import { getComponentId } from '~utils/isValidAllowedChildren';

const _ChipGroup = (
{
Expand Down Expand Up @@ -68,6 +70,24 @@ const _ChipGroup = (
});
}
}
const isWrapperLayoutControlled =
typeof children === 'object' && getComponentId(children) === 'Box';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

            <BaseBox
              display="flex"
              flexDirection="row"
              flexWrap="wrap"
              rowGap={chipGroupGapTokens[size].bottom}
              columnGap={chipGroupGapTokens[size].right}
              marginBottom={chipGroupGapTokens[size].bottom}
            >
              {React.Children.map(children, (child, index) => {
                return <BaseBox key={index}>{child}</BaseBox>; // maybe we can remove the box if needed
              })}
            </BaseBox>

This code i shared, should just work without doing any of these checks/conditionals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I think we should add a wrapper and check for styles since consumers can pass props like background color or margin and padding, which should not be supported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not do arbitrary checks if it's absolutely not necessary. If they add background etc anyways it will look odd.

Your above code will fail in many cases like so:

const SomeCustomWrapperBox = styled(Box)``

<ChipGroup>
  <SomeCustomWrapperBox>
    ...
  </SomeCustomWrapperBox>
</ChipGroup>
``

const getChipGroupWrapperStyles = (): Record<string, unknown> => {
if (isWrapperLayoutControlled) {
return {
...(React.isValidElement(children) ? getLayOutProps(children.props) : {}),
};
}
return {};
};
const getChipWrapperChildren = (): React.ReactNode => {
if (isWrapperLayoutControlled) {
if (React.isValidElement(children) && children.props) {
return children.props.children;
}
}
return children;
};

return (
<ChipGroupProvider value={contextValue}>
Expand Down Expand Up @@ -96,8 +116,13 @@ const _ChipGroup = (
<VisuallyHidden>
<Text>{accessibilityLabel}</Text>
</VisuallyHidden>
<BaseBox display="flex" flexDirection="row" flexWrap="wrap">
{React.Children.map(children, (child, index) => {
<BaseBox
display="flex"
flexDirection="row"
flexWrap="wrap"
{...(isWrapperLayoutControlled ? getChipGroupWrapperStyles() : {})}
>
{React.Children.map(getChipWrapperChildren(), (child, index) => {
return (
<BaseBox
key={index}
Expand Down
29 changes: 28 additions & 1 deletion packages/blade/src/components/Chip/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
import type { StyledPropsBlade } from '~components/Box/styledProps';
import type { Theme } from '~components/BladeProvider';
import type { IconComponent } from '~components/Icons';
import type { DataAnalyticsAttribute, StringChildrenType, TestID } from '~utils/types';
import type {
DataAnalyticsAttribute,
PickCSSByPlatform,
StringChildrenType,
TestID,
} from '~utils/types';
import type { DotNotationToken } from '~utils/lodashButBetter/get';
import type { MotionMetaProp } from '~components/BaseMotion';
import type {
BaseBoxProps,
FlexboxProps,
GridProps,
} from '~components/Box/BaseBox/types/propsTypes';

type ChipGroupContainerLayoutProps = Omit<
Partial<PickCSSByPlatform<'display'> & FlexboxProps & GridProps>,
'__brand__'
>;

type ChipCommonProps = {
/**
Expand All @@ -29,6 +44,10 @@ type ChipCommonProps = {
* Use `onChange` to update its value
*/
value?: string;
/**
* width prop sets the width of the Chip
*/
width?: BaseBoxProps['width'];
} & TestID &
DataAnalyticsAttribute &
StyledPropsBlade &
Expand Down Expand Up @@ -137,6 +156,13 @@ type ChipGroupCommonProps = {
* @default "primary"
*/
color?: 'primary' | 'positive' | 'negative';
/**
* Layout properties for the ChipGroup container
* currently supports `display`, flex and grid properties
* @default { display: 'flex', flexDirection: 'row', flexWrap: 'wrap' }
*
*/
chipGroupContainerLayout?: ChipGroupContainerLayoutProps;
anuraghazra marked this conversation as resolved.
Show resolved Hide resolved
} & TestID &
DataAnalyticsAttribute &
StyledPropsBlade;
Expand Down Expand Up @@ -246,4 +272,5 @@ export type {
StyledChipWrapperProps,
ChipBorderColors,
ChipBackgroundColors,
ChipGroupContainerLayoutProps,
};
57 changes: 57 additions & 0 deletions packages/blade/src/components/Chip/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// ref - /blade/packages/blade/src/components/Box/styledProps/getStyledProps.ts
tewarig marked this conversation as resolved.
Show resolved Hide resolved
// since here the use case is too specific that's why makeLayout Prop is inside Chip.

import type { ChipGroupContainerLayoutProps } from './types';
import { removeUndefinedStyledProps } from '~components/Box/styledProps';
import type { KeysRequired } from '~utils/types';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type StyledPropsInputType = Record<string, any>;

const makeStyledProps = (
props: StyledPropsInputType,
): KeysRequired<ChipGroupContainerLayoutProps> => {
return {
display: props.display,
gridColumn: props.gridColumn,
gridRow: props.gridRow,
gridArea: props.gridArea,
alignSelf: props.alignSelf,
justifySelf: props.justifySelf,
placeSelf: props.placeSelf,
order: props.order,
gridColumnStart: props.gridColumnStart,
gridColumnEnd: props.gridColumnEnd,
alignContent: props.alignContent,
alignItems: props.alignItems,
columnGap: props.columnGap,
gap: props.gap,
gridAutoColumns: props.gridAutoColumns,
gridAutoFlow: props.gridAutoFlow,
gridAutoRows: props.gridAutoRows,
gridTemplateAreas: props.gridTemplateAreas,
grid: props.grid,
gridTemplate: props.gridTemplate,
gridTemplateColumns: props.gridTemplateColumns,
gridTemplateRows: props.gridTemplateRows,
justifyContent: props.justifyContent,
justifyItems: props.justifyItems,
rowGap: props.rowGap,
flexBasis: props.flexBasis,
flexDirection: props.flexDirection,
flexGrow: props.flexGrow,
flexShrink: props.flexShrink,
flexWrap: props.flexWrap,
flex: props.flex,
placeItems: props.placeItems,
gridRowEnd: props.gridRowEnd,
gridRowStart: props.gridRowStart,
};
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getLayOutProps = (props: Record<string, any>): ChipGroupContainerLayoutProps => {
return removeUndefinedStyledProps(makeStyledProps(props));
};

export { getLayOutProps };
Loading