Skip to content

Commit

Permalink
refactor(radio): ✨ add optional chain, memo & separate group
Browse files Browse the repository at this point in the history
  • Loading branch information
navin-moorthy committed Jun 22, 2022
1 parent 2910b70 commit c2c0305
Show file tree
Hide file tree
Showing 16 changed files with 236 additions and 147 deletions.
42 changes: 26 additions & 16 deletions src/checkbox-group/CheckboxGroupProps.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from "react";
import { CheckboxState, CheckboxStateProps, useCheckboxState } from "ariakit";

import { CheckboxUIProps, Value } from "../checkbox";
Expand Down Expand Up @@ -39,10 +40,13 @@ export const useCheckboxGroupProps = ({
stack,
maxVisibleItems,
});
const uiProps: CheckboxGroupUIProps = {
state: withState ? state : undefined,
...uiState,
};
const uiProps: CheckboxGroupUIProps = React.useMemo(
() => ({
state: withState ? state : undefined,
...uiState,
}),
[state, uiState, withState],
);
const { componentProps, finalChildren } = getComponentProps(
componentMap,
children,
Expand All @@ -60,18 +64,24 @@ export const useCheckboxGroupProps = ({
? null
: (finalChildren.slice(uiProps.maxVisibleItems) as React.ReactNode);

const wrapperProps: CheckboxGroupWrapperProps = {
...uiProps,
...restProps,
...componentProps?.wrapperProps,
};
const wrapperProps: CheckboxGroupWrapperProps = React.useMemo(
() => ({
...uiProps,
...restProps,
...componentProps?.wrapperProps,
}),
[componentProps?.wrapperProps, restProps, uiProps],
);

const showMoreProps: CheckboxShowMoreProps = {
...uiProps,
direction: uiProps.stack,
...componentProps?.showMoreProps,
children: moreChildren,
};
const showMoreProps: CheckboxShowMoreProps = React.useMemo(
() => ({
...uiProps,
direction: uiProps.stack,
...componentProps?.showMoreProps,
children: moreChildren,
}),
[componentProps?.showMoreProps, moreChildren, uiProps],
);

return {
uiProps,
Expand All @@ -94,9 +104,9 @@ export type CheckboxGroupUIProps = CheckboxGroupUIState & {
};

export type CheckboxGroupPropsReturn = {
wrapperProps: CheckboxGroupWrapperProps;
uiProps: CheckboxGroupUIProps;
visibleChildren: React.ReactNode;
moreChildren: React.ReactNode;
wrapperProps: CheckboxGroupWrapperProps;
showMoreProps: CheckboxShowMoreProps;
};
3 changes: 2 additions & 1 deletion src/checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
labelProps,
inputProps,
iconProps,
textWrapperProps,
textProps,
descriptionProps,
uiProps,
Expand All @@ -24,7 +25,7 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
<CheckboxLabel {...labelProps}>
<CheckboxInput ref={ref} {...inputProps} />
<CheckboxIcon {...iconProps} />
<CheckboxTextWrapper>
<CheckboxTextWrapper {...textWrapperProps}>
{label ? <CheckboxText {...textProps} /> : null}
{label && description ? (
<CheckboxDescription {...descriptionProps} />
Expand Down
13 changes: 2 additions & 11 deletions src/radio-group/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,15 @@ export const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>(
visibleChildren,
moreChildren,
wrapperProps,
buttonProps,
contentProps,
showMoreProps,
uiProps,
} = useRadioGroupProps(props);

// TODO: Fix focus when show more is clicked while inside the content
return (
<RadioGroupWrapper ref={ref} {...wrapperProps}>
<RadioGroupContextProvider {...uiProps}>
{visibleChildren}
{moreChildren ? (
<RadioShowMore
moreChildren={moreChildren}
buttonProps={buttonProps}
contentProps={contentProps}
uiProps={uiProps}
/>
) : null}
{moreChildren ? <RadioShowMore {...showMoreProps} /> : null}
</RadioGroupContextProvider>
</RadioGroupWrapper>
);
Expand Down
55 changes: 30 additions & 25 deletions src/radio-group/RadioGroupProps.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { RadioState, RadioStateProps, useRadioState } from "ariakit";

import { RadioUIProps } from "../radio/RadioProps";
import { ShowMoreButtonProps, ShowMoreContentProps } from "../show-more";
import { getComponentProps, RenderProp } from "../utils";

import {
Expand All @@ -10,11 +10,11 @@ import {
useRadioGroupUIState,
} from "./RadioGroupUIState";
import { RadioGroupWrapperProps } from "./RadioGroupWrapper";
import { RadioShowMoreProps } from "./RadioShowMore";

const componentMap = {
RadioGroupWrapper: "wrapperProps",
ShowMoreContent: "contentProps",
ShowMoreButton: "buttonProps",
RadioShowMore: "showMoreProps",
};

export const useRadioGroupProps = ({
Expand Down Expand Up @@ -54,10 +54,13 @@ export const useRadioGroupProps = ({
stack,
maxVisibleItems,
});
const uiProps: RadioGroupUIProps = {
state: withState ? state : undefined,
...uiState,
};
const uiProps: RadioGroupUIProps = React.useMemo(
() => ({
state: withState ? state : undefined,
...uiState,
}),
[state, uiState, withState],
);
const { componentProps, finalChildren } = getComponentProps(
componentMap,
children,
Expand All @@ -75,27 +78,30 @@ export const useRadioGroupProps = ({
? null
: (finalChildren.slice(uiProps.maxVisibleItems) as React.ReactNode);

const wrapperProps: RadioGroupWrapperProps = {
...uiProps,
...restProps,
...componentProps?.wrapperProps,
};

const buttonProps: ShowMoreButtonProps = {
...componentProps?.buttonProps,
};

const contentProps: ShowMoreContentProps = {
...componentProps?.contentProps,
};
const wrapperProps: RadioGroupWrapperProps = React.useMemo(
() => ({
...uiProps,
...restProps,
...componentProps?.wrapperProps,
}),
[componentProps?.wrapperProps, restProps, uiProps],
);

const showMoreProps: RadioShowMoreProps = React.useMemo(
() => ({
...uiProps,
direction: uiProps.stack,
...componentProps?.showMoreProps,
children: moreChildren,
}),
[componentProps?.showMoreProps, moreChildren, uiProps],
);
return {
uiProps,
visibleChildren,
moreChildren,
wrapperProps,
buttonProps,
contentProps,
showMoreProps,
};
};

Expand All @@ -111,10 +117,9 @@ export type RadioGroupUIProps = RadioGroupUIState & {
};

export type RadioGroupPropsReturn = {
wrapperProps: RadioGroupWrapperProps;
contentProps: ShowMoreContentProps;
buttonProps: ShowMoreButtonProps;
uiProps: RadioGroupUIProps;
visibleChildren: React.ReactNode;
moreChildren: React.ReactNode;
wrapperProps: RadioGroupWrapperProps;
showMoreProps: RadioShowMoreProps;
};
6 changes: 3 additions & 3 deletions src/radio-group/RadioGroupWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { RadioGroupUIProps } from "./RadioGroupProps";

export const useRadioGroupWrapper = createHook<RadioGroupWrapperOptions>(
({ state, size, themeColor, stack, maxVisibleItems, prefix, ...props }) => {
const theme = useTheme("radio");
const theme = useTheme("radioGroup");
const className = cx(
stack ? theme.group[stack] : "",
stack && size ? theme.group.size[size]?.[stack] : "",
stack ? theme[stack] : "",
stack && size ? theme.size[size]?.[stack] : "",
props.className,
);

Expand Down
50 changes: 26 additions & 24 deletions src/radio-group/RadioShowMore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,51 @@ import * as React from "react";

import { PlusIcon } from "../icons";
import {
ShowMore,
ShowMoreButton,
ShowMoreButtonProps,
ShowMoreContent,
ShowMoreContentProps,
ShowMoreProps,
useShowMoreProps,
} from "../show-more";
import { useTheme } from "../theme";
import { cx, passProps } from "../utils";

import { RadioGroupUIProps } from "./RadioGroupProps";

export type RadioShowMoreProps = {
contentProps: ShowMoreContentProps;
buttonProps: ShowMoreButtonProps;
uiProps: RadioGroupUIProps;
moreChildren: React.ReactNode;
};

export const RadioShowMore: React.FC<RadioShowMoreProps> = props => {
const { contentProps, moreChildren, buttonProps, uiProps } = props;
const { stack, size, themeColor } = uiProps;
export type RadioShowMoreProps = ShowMoreProps &
Partial<RadioGroupUIProps> & {};

export const RadioShowMore: React.FC<RadioShowMoreProps> = ({
state,
size,
themeColor,
stack = "horizontal",
maxVisibleItems,
prefix,
...props
}) => {
const { buttonProps, contentProps } = useShowMoreProps(props);
const children = contentProps.children as React.ReactNode;

const [hasExpandStarted, setHasExpandStarted] = React.useState(false);
const finalChildren = React.Children.map(children, child => {
return passProps(child, { disabled: hasExpandStarted ? false : true });
});

const theme = useTheme("radio");
const theme = useTheme("radioGroup");
const buttonClassName = cx(
theme.group.showMore.button.common[stack],
hasExpandStarted ? "" : theme.group.showMore.button.expanded[stack],
theme.showMore.button.common[stack],
hasExpandStarted ? "" : theme.showMore.button.expanded[stack],
);
const contentClassName = cx(theme.group.showMore.content[stack]);

const finalChildren = React.Children.map(moreChildren, child => {
return passProps(child, { disabled: hasExpandStarted ? false : true });
});
const contentClassName = cx(theme.showMore.content[stack]);

return (
<ShowMore direction={stack}>
{finalChildren}
<>
<ShowMoreContent
className={contentClassName}
onExpandStart={() => setHasExpandStarted(true)}
onCollapseStart={() => setHasExpandStarted(false)}
{...contentProps}
children={finalChildren}
/>
<ShowMoreButton
variant="ghost"
Expand All @@ -54,7 +56,7 @@ export const RadioShowMore: React.FC<RadioShowMoreProps> = props => {
className={buttonClassName}
{...buttonProps}
/>
</ShowMore>
</>
);
};

Expand Down
9 changes: 4 additions & 5 deletions src/radio/Radio.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import * as React from "react";

import { cx } from "../utils";

import { RadioDescription } from "./RadioDescription";
import { RadioIcon } from "./RadioIcon";
import { RadioInput } from "./RadioInput";
import { RadioLabel } from "./RadioLabel";
import { RadioProps, useRadioProps } from "./RadioProps";
import { RadioText } from "./RadioText";
import { RadioTextWrapper } from "./RadioTextWrapper";

export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
(props, ref) => {
const {
labelProps,
inputProps,
iconProps,
textWrapperProps,
textProps,
descriptionProps,
uiProps,
Expand All @@ -25,13 +25,12 @@ export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
<RadioLabel {...labelProps}>
<RadioInput ref={ref} {...inputProps} />
<RadioIcon {...iconProps} />
{/* TODO: Create a new component & check for shadows */}
<div className={cx(label && !description ? "flex items-center" : "")}>
<RadioTextWrapper {...textWrapperProps}>
{label ? <RadioText {...textProps} /> : null}
{label && description ? (
<RadioDescription {...descriptionProps} />
) : null}
</div>
</RadioTextWrapper>
</RadioLabel>
);
},
Expand Down
12 changes: 6 additions & 6 deletions src/radio/RadioDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ export const useRadioDescription = createHook<RadioDescriptionOptions>(
const theme = useTheme("radio");
const className = cx(
theme.description,
size ? theme.size[size].description : "",
size ? theme.size[size]?.description : "",
themeColor
? !disabled
? cx(
theme.themeColor[themeColor].default.description,
theme.themeColor[themeColor].hover.description,
theme.themeColor[themeColor].active.description,
theme.themeColor[themeColor].focus.description,
theme.themeColor[themeColor]?.default?.description,
theme.themeColor[themeColor]?.hover?.description,
theme.themeColor[themeColor]?.active?.description,
theme.themeColor[themeColor]?.focus?.description,
)
: theme.themeColor[themeColor].disabled.description
: theme.themeColor[themeColor]?.disabled?.description
: "",
props.className,
);
Expand Down
Loading

0 comments on commit c2c0305

Please sign in to comment.