nextui/packages/components/radio/stories/radio.stories.tsx
Junior Garcia dc0bcf13a5
v2.3.0 [WIP] (#2618)
* refactor(input): input ref test (#2613)

* refactor(input): remove duplicate test

* refactor(input): remove unncessary waitFor

* fix(radio): isRequired & missing warning message in Form (#2597)

* fix(radio): avoid overriding required props

* fix(radio): merge with domRef

* feat(changeset): fixed missing required props and validationMessage

* fix(radio): unnecessary mergeRefs

* Calendar component  📅 (#2456)

* feat(calendar): initial structure

* feat(calendar): calendar structure completed, styles in progress

* chore(calendar): dark colors adjusted

* feat(calendar): styles improved, variants added, animations added with framer motion

* chore(calendar): animation changed, shadow improved

* chore(calendar): disableAnimation support added as well as weekDays format

* feat(calendar): more stories added

* chore(calendar): refactor calendar cell styling

* feat(calendar): create calendar function added to the root provider

* feat(calendar): invalid state and error message added

* feat(calendar): calendar picker added, provider modified

* feat(root): object.values deps replaced by new func, intersection hoook added, types version unified

* feat(calendar): calendar pickers in progress

* feat(calendar): calendar pickers added

* fix(calendar): year label formatting

* chore(calendar): add layout parameter to Calendar stories

* feat(calendar): pickers completed, context added

* feat(calendar): visibleMonths supported, warnings fixed, tests added

* chore(root): changeset

* chore(calendar): add topContent and bottomContent props to calendar

* feat(calendar): add @nextui-org/radio package and update calendar component

* refactor: assigned type(DateValue) to focusedDate(ControlledFocusedVaue) (#2637)

Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de>

* Range Calendar 📆 (#2634)

* feat(calendar): range calendar added, calendar and context adapted

* feat(calendar): range calendar stories added

* chore(calendar): range calendar tests added

* fix(calendar): update calendar styles to adjust to dynamic width

* Date Input 🗓️ (#2641)

* feat(date-picker): date field component initialized

* chore(date-picker): date field renamed to date-input

* feat(date-picker): date input completed

* chore(date-input): commented code removed

* feat(avatar): support slots in AvatarGroup (#2669)

* feat: rename newPost to new (#2665)

* fix(avatar): spread getAvatarGroupCountProps in avatar count

* feat(avatar): support slots in avatarGroup

* feat(avatar): support classNames and add getAvatarGroupCountProps

* feat(docs): add classNames to avatar group

* feat(avatar): add CustomSlots in avatar group

* feat(changeset): support slots in avatar group

---------

Co-authored-by: winches <96854855+winchesHe@users.noreply.github.com>

* Date Picker Component 🗓️ (#2652)

* feat(date-picker): first iteration

* chore(date-picker): update date-picker README.md with improved description

* feat(date-picker): code organized, integration done

* fix(date-picker): min and max value + styles

* fix(date-picker): popover offset adn calendar styles

* feat(date-picker): stories added

* fix(date-picker): calendar width properly handled

* feat(date-picker): styles simplified

* chore(date-picker): almost all test passing

* fix(date-picker): test and styles

* chore(date-picker): calendar popover tests added

* fix(date-picker): props to be passed to the date-input

* TimeInput Component 🕒 (#2672)

* feat(time-input): time input added with some stories, tests and date-picker integration missing

* feat(time-input): tests added, date-picker integration added, missing stories added

* chore(react): missing packages added

* chore(time-input): fix stories names

* fix(time-input): time value type

* fix: date-picker visibleMonth width does not get widen enough (#2703)

* DateRangePicker Component 🗓️ (#2682)

* chore(date-range-picker): in progress

* chore(date-range-picker): in progress

* feat(date-input): components separated into multiple pieces to be able to implement the date range picker

* feat(date-range-picker): first version of it working

* chore(date-picker): hyphen symbol changed

* feat(date-range-picker): stories done

* fix(range-calendar): styles

* docs: Calendar & RangeCalendar (#2686)

* feat(docs): add calendar in routes.json

* feat(docs): refresh search-meta.json

* feat(docs): add calendar examples

* feat(docs): calendar content

* feat(deps): add @internationalized/date

* refactor(docs): remove div wrapper

* feat(docs): add calendar doc

* fix(docs): calendar presets

* fix(docs): preset styles

* chore(docs): remove calendar iframe examples

* refactor(docs): discard iframe in calendar doc

* fix(docs): incorrect DateValue import

* feat(docs): include @internationalized/date in live demo scope

* feat(docs): add presets description

* chore(docs): update search-meta.json

* fix(docs): remove DateValue

* feat(docs): include reactAriaI18n in react live demo scope

* fix(docs): presets import issue

* chore(docs): update search-meta.json

* feat(docs): add api reference for nextui provider

* fix(calendar): ixExpanded  typo

* feat(docs): add missing props & event

* chore(docs): update search-meta.json

* chore(docs): update route keywords

* chore(docs): revise value style add defaultFocusedValue

* chore(docs): remove padding and revise gap

* feat(docs): range calendar

* chore(docs): update search-meta.json

* feat(docs): add reactAriaHook

* fix(docs): incorrect component and add storybook and reactAriaHook

* fix(docs): incorrect import path

* chore(docs): reorder range calendar position in sidebar

* chore(Docs): remove custom styles & implementation

* chore(docs): remove last item from accessibility

* chore(docs): onValueChange -> onChange

* feat(docs): add ts example for range calendar

* chore(docs): remove unwanted content in range calendar

* feat(docs): add ts examples for calendar

* chore(docs): update import path

* chore(docs): update import path

* chore(docs): styles adjusted, routes updated

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* docs: TimeInput (#2698)

* feat(docs): add time input to routes.json

* feat(deps): add @internationalized/date

* feat(docs): add @internationalized/date and @react-aria/i18n to code demo scopes

* feat(docs): time input contetnt

* chore(docs): revise time input examples

* feat(docs): time input content

* chore(time-input): update description

* feat(docs): add ts examples in time-input

* chore(docs): revise TimeValue import

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* chore(date-picker): exports updated

* docs: DatePicker (#2700)

* docs: created the doc for datepicker and its examples

* docs: regenerate search-meta.json

* fix: reverted the unncessary change to Input component

* fix: fixed the component-link for date-picker

* fix: fixed the component-link for date-picker

* fix: added variants section to the doc

* fix: made adjustment to the explanations for the props of DatePicker comp

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* doc: DateInput (#2711)

* docs: created base examples and the document

* chore: created search-meta and follow-up fix for each date-input example cases

* fix: fixed some example components styles

* fix(docs): updated routes.json

* fix(docs): fixed typo in the docs

* fix: fixed the component-link for date-input

* fix: fixed the component-link for date-input

* fix: label-placements example flex style adjustment

* fix: added variants section to the doc

---------

Co-authored-by: HaRuki Kuriwada <haruki.kuriwada@hennge.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* refactor(theme): units removed, tailwind-variants upgraded (#2713)

* fix(theme): units replaced by spacing

* fix(select): positioning the label if a description is used (#2553)

Co-authored-by: Poli Sour <polisour.work@gmail.com>

* Upgrade to new react aria version (#2561)

* chore(root): pkg upgraded

* fix: type error

* fix: build error

* chore: update packages from a~d

* chore: update packages from i~r

* chore: update packages from s~u

* chore: update core, hooks, and utilities packages

* feat: add support radio group validationBehavior props

* fix: validationBehavior default to native

* chore: add validationBehavior props in RadioGroup Stories

* fix: handling of errorMessage

* chore: add support validationBehavior autocomplete

* chore: partial support for validation of select

* chore: add support validationBehavior checkbox

* chore: change validationBehavior default to native

* Merge branch 'v.2.3.0' into feat/upgrade-react-aria

* fix: validation logic

* fix: add default value for autocomplete

* chore: add example using error message function

* chore: fixed error displayed in storybook

* chore: omit validationBehavior from component props

* chore: update docs and storybook on validate

* fix: pnpm-lock version

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(core): build and date input / time input apis

* chore(date-picker): omit validation behavior

* chore(docs): add missing props to calendar and range calendar

* docs: add nextui-cli page (#2714)

* docs: add nextui-cli page

* docs: update search meta

* docs: typo

* docs: typo

* docs: typo

* feat(docs): cli docs done

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* chore(docs): add cli commands to installation docs

* fix(checkbox): prettier

* fix(docs): incorrect cli api references link

* doc: DateRangePicker (#2712)

* chore: created base for date-range-picker doc

* fix: added follow-up story examples to the doc

* fix: fixed bugs happening on the doc

* fix: fixed bugs happening on the doc

* fix(docs): incorrect file path and revise title

* fix: component examples style fixes

* fix: component presets typo fix

* refactor(core): date range picker docs completed, standaline date picker field fixed

---------

Co-authored-by: HaRuki Kuriwada <haruki.kuriwada@hennge.com>
Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix: only two keyframes currently supported with spring and inertia animations (#2596)

* chore(deps): bump framer-motion

* feat(changeset): fixed framer motion issue

* chore(changeset): revise changeset message

* chore(deps): update pnpm-lock.yaml

* fix: react hook form issue (#2603)

* fix(input): pass domRef?.current?.value to controlled state

* fix(input): pass domRef?.current?.value to useTextField instead

* fix(checkbox): handle RHF case

* fix(checkbox): add missing isSelected case

* chore(checkbox): update ref type

* chore(deps): add @nextui-org/use-safe-layout-effect

* chore(deps): update pnpm-lock.yaml

* chore(deps): update pnpm-lock.yaml

* fix(select): handle RHF case

* chore(deps): add @nextui-org/use-safe-layout-effect to select

* fix(autocomplete): handle RHF case

* chore(deps): add @nextui-org/use-safe-layout-effect to autocomplete

* refactor(components): revise comments

* feat(changeset): react-hook-form uncontrolled components

* chore(deps): pnpm-lock.yaml

* fix(input): domRef.current.value has higher precedence

* fix(checkbox): set isChecked based on input ref checked

* feat(components): tabs component add tabPosition prop (#2398)

* feat(components): tabs component add tabPosition prop

* fix: review problem change

* test: add tabs position vertical test

* docs: update changeset

* fix(tabs): optimize return of tabs

* fix(tabs): rename orientation to placement

* fix(tabs): optimize description

* chore(docs): routes

* fix: isReadOnly in Autocomplete MDX (#2444)

* feat(autocomplete): add isReadOnly example

* fix(autocomplete): isReadOnly logic in Autocomplete

* feat(root): add changeset - fixed isReadOnly logic in Autocomplete

* chore(autocomplete component) isReadOnly property demo

isReadOnly property demo in website MDX for autocomplete component.

* Update apps/docs/content/docs/components/autocomplete.mdx

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com>
Co-authored-by: Alpha <116849110+alpha-xek@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(select): only trigger setSelectedKeys when domRef.current.value is true (#2722)

* chore(docs): blog changes (#2724)

* chore(docs): blog changes

* feat(docs): blog improved

* chore(blog): draft param added

* chore: version changeset added

* feat(blog): v2.3.0 almost done

* chore(docs): tailwind colors updated, calendar overflow fixed

* chore(blog): add presets demo

* fix(calendar): overflow on windows

* chore(docs): improve popover placements demo

* fix(autocomplete): set shouldUseVirtualFocus to false in getListboxProps (#2731)

* chore(blog): add cotributors

* chore(blog): draft

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>
Co-authored-by: Shrinidhi Upadhyaya <shrinidhiupadhyaya1195@gmail.com>
Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de>
Co-authored-by: winches <96854855+winchesHe@users.noreply.github.com>
Co-authored-by: HaRuki <soccer_haruki15@me.com>
Co-authored-by: HaRuki Kuriwada <haruki.kuriwada@hennge.com>
Co-authored-by: Poli Sour <57824881+novsource@users.noreply.github.com>
Co-authored-by: Poli Sour <polisour.work@gmail.com>
Co-authored-by: Ryo Matsukawa <76232929+ryo-manba@users.noreply.github.com>
Co-authored-by: winches <329487092@qq.com>
Co-authored-by: Alpha Xek <116849110+alphaxek@users.noreply.github.com>
Co-authored-by: Alpha <116849110+alpha-xek@users.noreply.github.com>
2024-04-16 09:25:51 -03:00

417 lines
8.6 KiB
TypeScript

import type {ValidationResult} from "@react-types/shared";
import React from "react";
import {Meta} from "@storybook/react";
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {radio, button} from "@nextui-org/theme";
import {clsx} from "@nextui-org/shared-utils";
import {
RadioGroup,
Radio,
RadioProps,
RadioGroupProps,
useRadio,
useRadioGroupContext,
} from "../src";
export default {
title: "Components/RadioGroup",
component: RadioGroup,
onChange: {action: "changed"},
argTypes: {
color: {
control: {
type: "select",
},
options: ["default", "primary", "secondary", "success", "warning", "danger"],
},
size: {
control: {
type: "select",
},
options: ["sm", "md", "lg"],
},
isDisabled: {
control: {
type: "boolean",
},
},
},
} as Meta<typeof RadioGroup>;
const defaultProps = {
...radio.defaultVariants,
label: "Options",
};
const Template = (args: RadioGroupProps) => {
const radioProps = args.description
? {
a: {
description: "Description for Option A",
},
b: {
description: "Description for Option B",
},
c: {
description: "Description for Option C",
},
d: {
description: "Description for Option D",
},
}
: {
a: {},
b: {},
c: {},
d: {},
};
const items = (
<>
<Radio value="A" {...radioProps.a}>
Option A
</Radio>
<Radio value="B" {...radioProps.b}>
Option B
</Radio>
<Radio value="C" {...radioProps.c}>
Option C
</Radio>
<Radio value="D" {...radioProps.d}>
Option D
</Radio>
</>
);
return args.isRequired ? (
<form
className="flex flex-col items-start gap-4"
onSubmit={(e) => {
alert(`Submitted value: ${e.target["sample"].value}`);
e.preventDefault();
}}
>
<RadioGroup {...args} name="sample">
{items}
</RadioGroup>
<button className={button({color: "primary"})} type="submit">
Submit
</button>
</form>
) : (
<RadioGroup {...args}>{items}</RadioGroup>
);
};
const InvalidTemplate = (args: RadioGroupProps) => {
const [isInvalid, setIsInvalid] = React.useState<boolean>(true);
const radioProps = args.description
? {
a: {
description: "Description for Option A",
},
b: {
description: "Description for Option B",
},
c: {
description: "Description for Option C",
},
d: {
description: "Description for Option D",
},
}
: {
a: {},
b: {},
c: {},
d: {},
};
const items = (
<>
<Radio value="A" {...radioProps.a}>
Option A (Invalid)
</Radio>
<Radio value="B" {...radioProps.b}>
Option B (Valid)
</Radio>
<Radio value="C" {...radioProps.c}>
Option C (Valid)
</Radio>
<Radio value="D" {...radioProps.d}>
Option D (Invalid)
</Radio>
</>
);
const validOptions = ["C", "B"];
return args.isRequired ? (
<form
className="flex flex-col items-start gap-4"
onSubmit={(e) => {
e.preventDefault();
alert("Submitted!");
}}
>
<RadioGroup
{...args}
isInvalid={isInvalid}
onValueChange={(value) => setIsInvalid(!validOptions.includes(value))}
>
{items}
</RadioGroup>
<button className={button({color: "primary"})} type="submit">
Submit
</button>
</form>
) : (
<RadioGroup {...args}>{items}</RadioGroup>
);
};
const ControlledTemplate = (args: RadioGroupProps) => {
const [selectedItem, setSelectedItem] = React.useState<string>("london");
React.useEffect(() => {
// eslint-disable-next-line no-console
console.log("isSelected:", selectedItem);
}, [selectedItem]);
return (
<div className="flex flex-col gap-2">
<RadioGroup
label="Select city"
value={selectedItem}
onValueChange={setSelectedItem}
{...args}
>
<Radio value="buenos-aires">Buenos Aires</Radio>
<Radio value="sydney">Sydney</Radio>
<Radio value="london">London</Radio>
<Radio value="tokyo">Tokyo</Radio>
</RadioGroup>
<p className="text-default-500">Selected: {selectedItem}</p>
</div>
);
};
export const Default = {
render: Template,
args: {
...defaultProps,
},
};
export const IsDisabled = {
render: Template,
args: {
...defaultProps,
isDisabled: true,
},
};
export const DefaultChecked = {
render: Template,
args: {
...defaultProps,
defaultValue: "C",
},
};
export const IsRequired = {
render: Template,
args: {
...defaultProps,
isRequired: true,
},
};
export const WithDescription = {
render: Template,
args: {
...defaultProps,
description: "Please select an option",
},
};
export const IsInvalid = {
render: InvalidTemplate,
args: {
...defaultProps,
isRequired: true,
description: "Please select an option",
},
};
export const WithErrorMessage = {
render: Template,
args: {
...defaultProps,
isRequired: true,
isInvalid: true,
errorMessage: "The selected option is invalid",
},
};
export const WithErrorMessageFunction = {
render: Template,
args: {
...defaultProps,
isRequired: true,
errorMessage: (value: ValidationResult) => {
if (value.validationDetails.valueMissing) {
return "Please select an option";
}
},
},
};
export const WithValidation = {
render: Template,
args: {
...defaultProps,
isRequired: true,
description: "Please select an option",
validate: (value: string) => {
if (value === "A") {
return "Option A is not allowed";
}
},
},
};
export const Row = {
render: Template,
args: {
...defaultProps,
orientation: "horizontal",
},
};
export const DisableAnimation = {
render: Template,
args: {
...defaultProps,
disableAnimation: true,
},
};
export const Controlled = {
render: ControlledTemplate,
args: {
...defaultProps,
},
};
const CustomRadio = (props: RadioProps) => {
const {children, ...otherProps} = props;
const {groupState} = useRadioGroupContext();
const isSelected = groupState.selectedValue === otherProps.value;
return (
<Radio
{...otherProps}
classNames={{
base: clsx(
"inline-flex bg-content1 hover:bg-content2 items-center justify-between flex-row-reverse max-w-[300px] cursor-pointer rounded-lg gap-4 p-4 border-2 border-transparent",
{
"border-primary": isSelected,
},
),
}}
>
{children}
</Radio>
);
};
export const CustomWithClassNames = () => {
return (
<RadioGroup label="Plans">
<CustomRadio description="Up to 20 items" value="free">
Free
</CustomRadio>
<CustomRadio description="Unlimited items. $10 per month." value="pro">
Pro
</CustomRadio>
<CustomRadio description="24/7 support. Contact us for pricing." value="enterprise">
Enterprise
</CustomRadio>
</RadioGroup>
);
};
const RadioCard = (props: RadioProps) => {
const {
Component,
children,
isSelected,
description,
getBaseProps,
getWrapperProps,
getInputProps,
getLabelProps,
getLabelWrapperProps,
getControlProps,
} = useRadio(props);
return (
<Component
{...getBaseProps()}
className={clsx(
"group inline-flex items-center justify-between hover:bg-content2 flex-row-reverse max-w-[300px] cursor-pointer border-2 border-default rounded-lg gap-4 p-4",
{
"border-primary": isSelected,
},
)}
>
<VisuallyHidden>
<input {...getInputProps()} />
</VisuallyHidden>
<span {...getWrapperProps()}>
<span {...getControlProps()} />
</span>
<div {...getLabelWrapperProps()}>
{children && <span {...getLabelProps()}>{children}</span>}
{description && (
<span className={clsx("text-sm text-foreground opacity-70")}>{description}</span>
)}
</div>
</Component>
);
};
export const CustomWithHooks = () => {
return (
<RadioGroup label="Plans">
<RadioCard description="Up to 20 items" value="free">
Free
</RadioCard>
<RadioCard description="Unlimited items. $10 per month." value="pro">
Pro
</RadioCard>
<RadioCard description="24/7 support. Contact us for pricing." value="enterprise">
Enterprise
</RadioCard>
</RadioGroup>
);
};