Skip to content

Commit de17901

Browse files
committed
feat(radio): ✨ make the selected radio in group always visible
1 parent cd2aa45 commit de17901

File tree

4 files changed

+77
-21
lines changed

4 files changed

+77
-21
lines changed

src/radio-group/RadioGroupProps.tsx

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { RadioState, RadioStateProps, useRadioState } from "ariakit";
44
import { RadioUIProps } from "../radio/RadioProps";
55
import { getComponentProps, RenderProp } from "../utils";
66

7+
import { getIndexOfActiveItem } from "./__utils";
78
import {
89
RadioGroupUIState,
910
RadioGroupUIStateProps,
@@ -18,7 +19,6 @@ const componentMap = {
1819
};
1920

2021
export const useRadioGroupProps = ({
21-
withState = true,
2222
value,
2323
defaultValue,
2424
setValue,
@@ -44,9 +44,23 @@ export const useRadioGroupProps = ({
4444
...restProps
4545
}: RadioGroupProps): RadioGroupPropsReturn => {
4646
const state = useRadioState({
47-
defaultValue,
4847
value,
48+
defaultValue,
4949
setValue,
50+
virtualFocus,
51+
orientation,
52+
rtl,
53+
focusLoop,
54+
focusWrap,
55+
focusShift,
56+
moves,
57+
setMoves,
58+
includesBaseElement,
59+
activeId,
60+
defaultActiveId,
61+
setActiveId,
62+
items,
63+
setItems,
5064
});
5165
const uiState = useRadioGroupUIState({
5266
size,
@@ -56,28 +70,17 @@ export const useRadioGroupProps = ({
5670
});
5771
const uiProps: RadioGroupUIProps = React.useMemo(
5872
() => ({
59-
state: withState ? state : undefined,
73+
state,
6074
...uiState,
6175
}),
62-
[state, uiState, withState],
76+
[state, uiState],
6377
);
6478
const { componentProps, finalChildren } = getComponentProps(
6579
componentMap,
6680
children,
6781
uiProps,
6882
);
6983

70-
const visibleChildren: React.ReactNode =
71-
uiProps.maxVisibleItems == null
72-
? (finalChildren as React.ReactNode)
73-
: (finalChildren.slice(0, uiProps.maxVisibleItems) as React.ReactNode);
74-
75-
const moreChildren: React.ReactNode =
76-
uiProps.maxVisibleItems == null ||
77-
finalChildren.length <= uiProps.maxVisibleItems
78-
? null
79-
: (finalChildren.slice(uiProps.maxVisibleItems) as React.ReactNode);
80-
8184
const wrapperProps: RadioGroupWrapperProps = React.useMemo(
8285
() => ({
8386
...uiProps,
@@ -87,14 +90,48 @@ export const useRadioGroupProps = ({
8790
[componentProps?.wrapperProps, restProps, uiProps],
8891
);
8992

93+
const [itemsInternal, setItemsInternal] = React.useState(finalChildren);
94+
95+
const visibleChildren =
96+
uiProps.maxVisibleItems == null
97+
? itemsInternal
98+
: itemsInternal.slice(0, uiProps.maxVisibleItems);
99+
100+
const moreChildren =
101+
uiProps.maxVisibleItems == null ||
102+
itemsInternal.length <= uiProps.maxVisibleItems
103+
? null
104+
: itemsInternal.slice(uiProps.maxVisibleItems);
105+
106+
const onCollapseStart = React.useCallback(() => {
107+
componentProps?.showMoreProps?.onCollapseStart?.();
108+
109+
const indexOfActiveItem = getIndexOfActiveItem(state.items, state.activeId);
110+
if (maxVisibleItems != null && indexOfActiveItem >= maxVisibleItems) {
111+
// Swap the radios to the end of the VisibleChildren
112+
const activeChildren = itemsInternal[indexOfActiveItem];
113+
itemsInternal[indexOfActiveItem] = itemsInternal[maxVisibleItems - 1];
114+
itemsInternal[maxVisibleItems - 1] = activeChildren;
115+
116+
setItemsInternal(itemsInternal);
117+
}
118+
}, [
119+
componentProps?.showMoreProps,
120+
itemsInternal,
121+
maxVisibleItems,
122+
state.activeId,
123+
state.items,
124+
]);
125+
90126
const showMoreProps: RadioShowMoreProps = React.useMemo(
91127
() => ({
92128
...uiProps,
93129
direction: uiProps.stack,
94130
...componentProps?.showMoreProps,
131+
onCollapseStart: onCollapseStart,
95132
children: moreChildren,
96133
}),
97-
[componentProps?.showMoreProps, moreChildren, uiProps],
134+
[componentProps?.showMoreProps, moreChildren, onCollapseStart, uiProps],
98135
);
99136
return {
100137
uiProps,
@@ -108,12 +145,11 @@ export const useRadioGroupProps = ({
108145
export type RadioGroupProps = RadioStateProps &
109146
Omit<RadioGroupWrapperProps, "state" | "size" | "children" | "defaultValue"> &
110147
RadioGroupUIStateProps & {
111-
withState?: boolean;
112148
children?: RenderProp<RadioUIProps>;
113149
};
114150

115151
export type RadioGroupUIProps = RadioGroupUIState & {
116-
state?: RadioState;
152+
state: RadioState;
117153
};
118154

119155
export type RadioGroupPropsReturn = {

src/radio-group/RadioShowMore.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,26 @@ export const RadioShowMore: React.FC<RadioShowMoreProps> = ({
3939
);
4040
const contentClassName = cx(theme.showMore.content[stack]);
4141

42+
const onExpandStart = () => {
43+
contentProps?.onExpandStart?.();
44+
45+
setHasExpandStarted(true);
46+
};
47+
48+
const onCollapseStart = () => {
49+
contentProps?.onCollapseStart?.();
50+
51+
setHasExpandStarted(false);
52+
};
53+
4254
return (
4355
<>
4456
<ShowMoreContent
4557
className={contentClassName}
46-
onExpandStart={() => setHasExpandStarted(true)}
47-
onCollapseStart={() => setHasExpandStarted(false)}
4858
{...contentProps}
4959
children={finalChildren}
60+
onExpandStart={onExpandStart}
61+
onCollapseStart={onCollapseStart}
5062
/>
5163
<ShowMoreButton
5264
variant="ghost"

src/radio-group/__utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { RadioState } from "ariakit";
2+
13
import { createContext } from "../utils";
24

35
import { RadioGroupUIProps } from "./RadioGroupProps";
@@ -9,3 +11,10 @@ const [RadioGroupContextProvider, useRadioGroupContext] =
911
});
1012

1113
export { RadioGroupContextProvider, useRadioGroupContext };
14+
15+
export const getIndexOfActiveItem = (
16+
items: RadioState["items"],
17+
activeId: RadioState["activeId"],
18+
) => {
19+
return items.findIndex(item => item.id === activeId);
20+
};

src/radio-group/stories/RadioGroupBasic.stories.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ export default {
3838
"clickOnSpace",
3939
"isChecked",
4040
"stack",
41-
"maxVisibleItems",
4241
"items",
4342
"setItems",
4443
"orientation",

0 commit comments

Comments
 (0)