mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
* 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>
417 lines
8.6 KiB
TypeScript
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>
|
|
);
|
|
};
|