Skip to content

Commit c6f19c5

Browse files
committed
feat(uniform): add fullWidth and content styling to RadioTabs
1 parent eeed7fe commit c6f19c5

File tree

3 files changed

+266
-41
lines changed

3 files changed

+266
-41
lines changed

packages/uniform/src/RadioTabs/RadioTabs.stories.tsx

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,6 @@ export const Default: Story = {
4444
},
4545
};
4646

47-
export const WithContent: Story = {
48-
args: {
49-
name: 'radioTabsField',
50-
options: [
51-
{ value: 'option_1', label: 'Option 1', content: 'Option 1 Content' },
52-
{ value: 'option_2', label: 'Option 2', content: 'Option 2 Content' },
53-
{ value: 'option_3', label: 'Option 3', content: 'Option 3 Content' },
54-
],
55-
},
56-
};
57-
5847
export const WithInitialValue: Story = {
5948
parameters: {
6049
formProps: { initialValues: { radioTabsField: 'option_2' } },
@@ -103,7 +92,7 @@ const requiredValidation = veto({
10392
export const Required: Story = {
10493
parameters: { formProps: { validation: requiredValidation } },
10594
args: {
106-
label: 'radioTabsField',
95+
label: 'Radio Tabs Field',
10796
name: 'radioTabsField',
10897
options: [
10998
{ value: 'option_1', label: 'Option 1' },
@@ -125,7 +114,7 @@ export const Invalid: Story = {
125114
},
126115
args: {
127116
name: 'radioTabsField',
128-
label: 'radioTabsField',
117+
label: 'Radio Tabs Field',
129118
testId: 'radioTabsField',
130119
options: [
131120
{ value: 'option_1', label: 'Option 1' },
@@ -141,3 +130,39 @@ export const Invalid: Story = {
141130
});
142131
},
143132
};
133+
134+
export const FullWidth: Story = {
135+
parameters: {
136+
formProps: {
137+
className: 'min-w-md',
138+
initialValues: { radioTabsField: 'option_1' },
139+
},
140+
},
141+
args: {
142+
label: 'Radio Tabs Field',
143+
fullWidth: true,
144+
name: 'radioTabsField',
145+
options: [
146+
{ value: 'option_1', label: 'Option 1' },
147+
{ value: 'option_2', label: 'Option 2' },
148+
{ value: 'option_3', label: 'Option 3' },
149+
],
150+
},
151+
};
152+
153+
export const WithContent: Story = {
154+
parameters: {
155+
formProps: {
156+
className: 'min-w-md',
157+
initialValues: { radioTabsField: 'option_1' },
158+
},
159+
},
160+
args: {
161+
name: 'radioTabsField',
162+
options: [
163+
{ value: 'option_1', label: 'Option 1', content: 'Option 1 Content' },
164+
{ value: 'option_2', label: 'Option 2', content: 'Option 2 Content' },
165+
{ value: 'option_3', label: 'Option 3', content: 'Option 3 Content' },
166+
],
167+
},
168+
};

packages/uniform/src/RadioTabs/RadioTabs.tsx

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,32 @@ import { FieldValidationError } from '../partials/FieldValidationError';
1515
export const radioTabsVariants = tv({
1616
slots: {
1717
base: 'group', // Needs group for group-data condition
18+
cursor: '',
1819
label:
1920
'text-foreground group-data-[invalid=true]:text-danger text-sm subpixel-antialiased',
20-
wrapper: '',
21-
tabList: '',
2221
tab: '',
22+
tabBase: '',
2323
tabContent: '',
24-
cursor: '',
25-
panel: '',
24+
tabList: '',
25+
tabPanel: 'p-3',
26+
tabWrapper: '',
27+
wrapper: '',
28+
},
29+
variants: {
30+
hasContent: {
31+
true: {
32+
base: 'w-full rounded-b-none p-1',
33+
tabBase: 'p-1 pb-0',
34+
tabList: 'w-full',
35+
tabWrapper: 'border-divider rounded-medium border',
36+
},
37+
},
38+
fullWidth: {
39+
true: {
40+
base: 'w-full',
41+
tabList: 'w-full',
42+
},
43+
},
2644
},
2745
});
2846

@@ -44,11 +62,13 @@ export interface RadioTabsOption {
4462
value: string;
4563
}
4664

47-
export interface RadioTabsProps extends VariantProps {
65+
export interface RadioTabsProps extends Omit<VariantProps, 'hasContent'> {
4866
/** CSS class name */
4967
className?: ClassName;
5068
/** Determines if the Buttons are disabled or not. */
5169
disabled?: boolean;
70+
/** Whether tabs should take up full container width */
71+
fullWidth?: boolean;
5272
/** determines orientation of the Buttons. */
5373
inline?: boolean;
5474
/** Label displayed next to the RadioButton. */
@@ -70,6 +90,7 @@ export interface RadioTabsProps extends VariantProps {
7090
const RadioTabs = ({
7191
className = undefined,
7292
disabled = false,
93+
fullWidth = false,
7394
inline = false,
7495
label = undefined,
7596
name,
@@ -86,7 +107,14 @@ const RadioTabs = ({
86107
const showTestIdCopyButton = debugMode === 'debug-testids';
87108
const showLabel = label ?? showTestIdCopyButton;
88109

89-
const variants = radioTabsVariants();
110+
// check if any option has content
111+
// eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/promise-function-async
112+
const hasContent = options.some((option) => {
113+
return option.content;
114+
});
115+
116+
// classNames from slots
117+
const variants = radioTabsVariants({ hasContent, fullWidth });
90118
const classNames = variantsToClassNames(variants, className, 'base');
91119

92120
const tabOptions = options.map<TabProps>((option) => {
@@ -108,7 +136,6 @@ const RadioTabs = ({
108136
return (
109137
<HeroRadioGroup
110138
ref={ref}
111-
classNames={classNames}
112139
// see HeroUI styles for group-data condition (data-invalid),
113140
// e.g.: https://github.com/heroui-inc/heroui/blob/main/packages/components/select/src/use-select.ts
114141
data-invalid={invalid}
@@ -120,6 +147,11 @@ const RadioTabs = ({
120147
name={name}
121148
onBlur={onBlur}
122149
orientation={inline ? 'horizontal' : 'vertical'}
150+
classNames={{
151+
base: classNames.base,
152+
label: classNames.label,
153+
wrapper: classNames.wrapper,
154+
}}
123155
errorMessage={
124156
error ? (
125157
<FieldValidationError error={error} testId={testId} />
@@ -139,13 +171,21 @@ const RadioTabs = ({
139171
>
140172
<Tabs
141173
disabledKeys={disabled ? disabledAllKeys : undefined}
142-
fullWidth={false}
143174
onSelectionChange={onChange}
144175
// make sure component is controlled
145176
selectedKey={value ?? ''}
146177
tabs={tabOptions}
147178
testId={testId}
148179
variant={variant}
180+
className={{
181+
base: classNames.tabBase,
182+
cursor: classNames.cursor,
183+
panel: classNames.tabPanel,
184+
tab: classNames.tab,
185+
tabContent: classNames.tabContent,
186+
tabList: classNames.tabList,
187+
tabWrapper: classNames.tabWrapper,
188+
}}
149189
/>
150190
</HeroRadioGroup>
151191
);

0 commit comments

Comments
 (0)