-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
299 additions
and
1 deletion.
There are no files selected for viewing
147 changes: 147 additions & 0 deletions
147
packages/storybook/src/components/radio/index.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import { | ||
Radio, | ||
RadioButton, | ||
RadioDescription, | ||
RadioDot, | ||
RadioField, | ||
RadioFields, | ||
RadioGroup, | ||
RadioGroupDescription, | ||
RadioGroupError, | ||
RadioGroupLabel, | ||
RadioLabel, | ||
} from "@spear-ai/ui/components/radio"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { Form } from "react-aria-components"; | ||
import { useIntl } from "react-intl"; | ||
|
||
const PreviewRadio = (properties: { | ||
firstOptionIsDisabled: boolean; | ||
firstOptionIsReadonly: boolean; | ||
groupIsDisabled: boolean; | ||
groupIsInvalid: boolean; | ||
hasGroupLabel: boolean; | ||
hasGroupLabelDescription: boolean; | ||
hasLabelDescription: boolean; | ||
isSquished: boolean; | ||
}) => { | ||
const { | ||
firstOptionIsDisabled, | ||
firstOptionIsReadonly, | ||
groupIsDisabled, | ||
groupIsInvalid, | ||
hasGroupLabel, | ||
hasGroupLabelDescription, | ||
hasLabelDescription, | ||
isSquished, | ||
} = properties; | ||
const intl = useIntl(); | ||
|
||
return ( | ||
<div className={`w-full ${isSquished ? "max-w-36" : "max-w-xs"}`}> | ||
<Form className="relative w-full"> | ||
<RadioGroup | ||
className="w-full" | ||
isDisabled={groupIsDisabled} | ||
isInvalid={groupIsInvalid} | ||
isReadOnly={firstOptionIsReadonly} | ||
isRequired | ||
validationBehavior="aria" | ||
> | ||
{hasGroupLabel ? ( | ||
<RadioGroupLabel> | ||
{intl.formatMessage({ | ||
defaultMessage: "Privacy", | ||
id: "cXBJ7U", | ||
})} | ||
</RadioGroupLabel> | ||
) : null} | ||
{hasGroupLabel && hasGroupLabelDescription ? ( | ||
<RadioGroupDescription> | ||
{intl.formatMessage({ | ||
defaultMessage: "Control your post’s privacy settings.", | ||
id: "dBZIgO", | ||
})} | ||
</RadioGroupDescription> | ||
) : null} | ||
<RadioFields> | ||
<RadioField> | ||
<Radio isDisabled={firstOptionIsDisabled} value="isLimitedToFriends"> | ||
<RadioButton> | ||
<RadioDot /> | ||
</RadioButton> | ||
<RadioLabel> | ||
{intl.formatMessage({ | ||
defaultMessage: "Show only to friends", | ||
id: "709cRj", | ||
})} | ||
</RadioLabel> | ||
</Radio> | ||
{hasLabelDescription ? ( | ||
<RadioDescription> | ||
{intl.formatMessage({ | ||
defaultMessage: "Whether only friends can see this post.", | ||
id: "WuPCNC", | ||
})} | ||
</RadioDescription> | ||
) : null} | ||
</RadioField> | ||
<RadioField> | ||
<Radio value="isShareable"> | ||
<RadioButton> | ||
<RadioDot /> | ||
</RadioButton> | ||
<RadioLabel> | ||
{intl.formatMessage({ | ||
defaultMessage: "Allow sharing", | ||
id: "MmQn2H", | ||
})} | ||
</RadioLabel> | ||
</Radio> | ||
{hasLabelDescription ? ( | ||
<RadioDescription> | ||
{intl.formatMessage({ | ||
defaultMessage: "Whether this post can be shared by others.", | ||
id: "qysWYY", | ||
})} | ||
</RadioDescription> | ||
) : null} | ||
</RadioField> | ||
</RadioFields> | ||
{groupIsInvalid ? ( | ||
<RadioGroupError> | ||
{intl.formatMessage({ | ||
defaultMessage: "There’s a problem with the selection", | ||
id: "Nfuwo5", | ||
})} | ||
</RadioGroupError> | ||
) : null} | ||
</RadioGroup> | ||
</Form> | ||
</div> | ||
); | ||
}; | ||
|
||
const meta = { | ||
component: PreviewRadio, | ||
} satisfies Meta<typeof PreviewRadio>; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Standard: Story = { | ||
args: { | ||
firstOptionIsDisabled: false, | ||
firstOptionIsReadonly: false, | ||
groupIsDisabled: false, | ||
groupIsInvalid: false, | ||
hasGroupLabel: true, | ||
hasGroupLabelDescription: true, | ||
hasLabelDescription: true, | ||
isSquished: false, | ||
}, | ||
parameters: { | ||
layout: "centered", | ||
}, | ||
}; | ||
|
||
export default meta; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import { Slot } from "@radix-ui/react-slot"; | ||
import { ComponentPropsWithoutRef, ElementRef, forwardRef, HTMLAttributes } from "react"; | ||
import { | ||
Label as LabelPrimitive, | ||
Radio as RadioPrimitive, | ||
RadioGroup as RadioGroupPrimitive, | ||
} from "react-aria-components"; | ||
import { cx } from "@/helpers/cx"; | ||
|
||
export const RadioGroup = forwardRef< | ||
ElementRef<typeof RadioGroupPrimitive>, | ||
ComponentPropsWithoutRef<typeof RadioGroupPrimitive> & { className?: string | undefined } | ||
>(({ className, ...properties }, reference) => { | ||
const mergedClassName = cx("group/group", className); | ||
return <RadioGroupPrimitive className={mergedClassName} {...properties} ref={reference} />; | ||
}); | ||
|
||
RadioGroup.displayName = "RadioGroup"; | ||
|
||
export const RadioGroupLabel = forwardRef< | ||
ElementRef<typeof LabelPrimitive>, | ||
ComponentPropsWithoutRef<typeof LabelPrimitive> | ||
>(({ className, ...properties }, reference) => { | ||
const mergedClassName = cx( | ||
"text-neutral-12 group-disabled/group:text-neutral-11 block select-none text-base/6 sm:text-sm/6", | ||
className, | ||
); | ||
return ( | ||
<LabelPrimitive className={mergedClassName} data-slot="group-label" {...properties} ref={reference} /> | ||
); | ||
}); | ||
|
||
RadioGroupLabel.displayName = "RadioGroupLabel"; | ||
|
||
export const RadioGroupDescription = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>( | ||
({ className, ...properties }, reference) => { | ||
const mergedClassName = cx( | ||
"text-neutral-11 group-disabled/group:text-neutral-9 mt-1 text-base/6 sm:text-sm/6", | ||
className, | ||
); | ||
return <p className={mergedClassName} data-slot="group-description" {...properties} ref={reference} />; | ||
}, | ||
); | ||
|
||
RadioGroupLabel.displayName = "RadioGroupDescription"; | ||
|
||
export const RadioGroupError = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>( | ||
({ className, ...properties }, reference) => { | ||
const mergedClassName = cx( | ||
"text-x-negative-11 group-disabled/group:text-x-negative-9 mt-3 text-sm", | ||
className, | ||
); | ||
return <p className={mergedClassName} data-slot="group-error" {...properties} ref={reference} />; | ||
}, | ||
); | ||
|
||
RadioGroupError.displayName = "RadioGroupError"; | ||
|
||
export const RadioFields = forwardRef< | ||
HTMLDivElement, | ||
HTMLAttributes<HTMLDivElement> & { asChild?: boolean | undefined } | ||
>(({ asChild = false, className, ...properties }, reference) => { | ||
const Component = asChild ? Slot : "div"; | ||
const mergedClassName = cx( | ||
"space-y-3 group-has-[[data-slot=group-description]]/group:mt-3 group-has-[[data-slot=group-label]]/group:mt-3", | ||
className, | ||
); | ||
return <Component aria-hidden className={mergedClassName} ref={reference} {...properties} />; | ||
}); | ||
|
||
RadioFields.displayName = "RadioFields"; | ||
|
||
export const RadioField = forwardRef< | ||
HTMLDivElement, | ||
HTMLAttributes<HTMLDivElement> & { asChild?: boolean | undefined } | ||
>(({ asChild = false, ...properties }, reference) => { | ||
const Component = asChild ? Slot : "div"; | ||
return <Component aria-hidden ref={reference} {...properties} />; | ||
}); | ||
|
||
RadioField.displayName = "RadioField"; | ||
|
||
export const Radio = forwardRef< | ||
ElementRef<typeof RadioPrimitive>, | ||
ComponentPropsWithoutRef<typeof RadioPrimitive> & { | ||
className?: string | undefined; | ||
isPrimary?: boolean | undefined; | ||
} | ||
>(({ className, isPrimary = false, ...properties }, reference) => { | ||
const mergedClassName = cx("group peer inline-flex", className); | ||
return ( | ||
<RadioPrimitive | ||
className={mergedClassName} | ||
data-is-primary={isPrimary} | ||
{...properties} | ||
ref={reference} | ||
/> | ||
); | ||
}); | ||
|
||
Radio.displayName = "Radio"; | ||
|
||
export const RadioLabel = forwardRef<HTMLSpanElement, HTMLAttributes<HTMLSpanElement>>( | ||
({ className, ...properties }, reference) => { | ||
const mergedClassName = cx( | ||
"text-neutral-12 group-invalid:text-x-negative-11 group-disabled:text-neutral-11 group-invalid:group-disabled:text-x-negative-9 -mt-1 flex-1 text-sm font-medium leading-6", | ||
className, | ||
); | ||
return <span className={mergedClassName} {...properties} ref={reference} />; | ||
}, | ||
); | ||
|
||
RadioLabel.displayName = "RadioLabel"; | ||
|
||
export const RadioDescription = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>( | ||
({ className, ...properties }, reference) => { | ||
const mergedClassName = cx( | ||
"text-neutral-11 peer-disabled:text-neutral-9 ms-7 text-sm leading-6", | ||
className, | ||
); | ||
return <p className={mergedClassName} {...properties} ref={reference} />; | ||
}, | ||
); | ||
|
||
RadioLabel.displayName = "RadioDescription"; | ||
|
||
export const RadioButton = forwardRef<HTMLSpanElement, HTMLAttributes<HTMLSpanElement>>( | ||
({ className, ...properties }, reference) => { | ||
const mergedClassName = cx( | ||
"border-neutral-a-7 bg-white-a-3 text-neutral-12 theme-dfs:bg-canvas-1 theme-galapago:bg-white group-invalid:border-x-negative-a-7 theme-dfs:group-invalid:border-x-negative-a-7 group-focus-visible:outline-primary-7 group-selected:border-transparent group-selected:bg-primary-9 group-selected:text-primary-contrast theme-forerunner:group-selected:bg-black-a-12 theme-forerunner:group-selected:text-white group-invalid:group-selected:border-x-negative-a-7 group-disabled:border-neutral-a-6 group-disabled:bg-neutral-a-3 group-disabled:text-neutral-a-8 theme-dfs:group-disabled:bg-neutral-a-3 theme-forerunner:group-disabled:border-neutral-a-6 theme-forerunner:group-disabled:bg-neutral-a-3 theme-forerunner:group-disabled:text-neutral-a-8 group-invalid:group-disabled:border-x-negative-a-6 theme-forerunner:group-invalid:group-disabled:border-x-negative-a-6 dark:bg-white-a-3 theme-dfs:dark:bg-white-a-3 theme-forerunner:dark:bg-black-a-3 theme-galapago:dark:bg-black-a-3 theme-dfs:group-selected:dark:border-neutral-a-7 theme-forerunner:group-selected:dark:border-neutral-a-7 theme-forerunner:group-selected:dark:bg-primary-a-5 theme-forerunner:group-selected:dark:text-primary-12 theme-galapago:dark:group-selected:bg-primary-a-9 theme-dfs:group-invalid:group-selected:dark:border-x-negative-a-7 theme-forerunner:group-invalid:group-selected:dark:border-x-negative-a-7 theme-galapago:dark:disabled:bg-neutral-a-3 theme-forerunner:group-disabled:dark:border-neutral-a-6 theme-forerunner:group-disabled:dark:bg-neutral-a-3 theme-forerunner:group-disabled:dark:text-neutral-a-8 theme-galapago:group-disabled:dark:bg-neutral-a-3 theme-galapago:group-disabled:dark:text-neutral-a-8 theme-forerunner:group-invalid:group-disabled:dark:border-x-negative-a-6 relative me-3 inline-flex size-4 items-center rounded-full border outline-offset-2 group-focus-visible:outline group-focus-visible:outline-2", | ||
className, | ||
); | ||
return <span className={mergedClassName} {...properties} ref={reference} />; | ||
}, | ||
); | ||
|
||
RadioButton.displayName = "RadioButton"; | ||
|
||
export const RadioDot = forwardRef< | ||
HTMLSpanElement, | ||
HTMLAttributes<HTMLSpanElement> & { asChild?: boolean | undefined } | ||
>(({ asChild = false, className, ...properties }, reference) => { | ||
const Component = asChild ? Slot : "span"; | ||
const mergedClassName = cx( | ||
"group-selected:opacity-100 absolute left-1 top-1 -ms-px -mt-px size-2 rounded-full bg-current opacity-0 group-indeterminate:!opacity-0", | ||
className, | ||
); | ||
return <Component aria-hidden className={mergedClassName} ref={reference} {...properties} />; | ||
}); | ||
|
||
RadioDot.displayName = "RadioDot"; |