mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(radio): almost complete, only tests missing
This commit is contained in:
parent
c12d54f1d2
commit
7b99e9f3f1
@ -2,14 +2,14 @@ import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import {Radio, RadioProps} from "../src";
|
||||
import {RadioGroup, Radio, RadioProps} from "../src";
|
||||
|
||||
describe("Radio", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(
|
||||
<Radio.Group label="Options">
|
||||
<RadioGroup label="Options">
|
||||
<Radio value="1">Option 1</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
@ -19,31 +19,31 @@ describe("Radio", () => {
|
||||
const ref = React.createRef<HTMLLabelElement>();
|
||||
|
||||
render(
|
||||
<Radio.Group label="Options">
|
||||
<RadioGroup label="Options">
|
||||
<Radio ref={ref} value="1">
|
||||
Option 1
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should work correctly with initial value", () => {
|
||||
let {container} = render(
|
||||
<Radio.Group label="Options" value="1">
|
||||
<RadioGroup label="Options" value="1">
|
||||
<Radio value="1">Option 1</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
expect(container.querySelector("input")?.checked).toBe(true);
|
||||
|
||||
let wrapper = render(
|
||||
<Radio.Group defaultValue="2" label="Options">
|
||||
<RadioGroup defaultValue="2" label="Options">
|
||||
<Radio value="1">Option 1</Radio>
|
||||
<Radio data-testid="radio-test-2" value="2">
|
||||
Option 1
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
let radio2 = wrapper.getByTestId("radio-test-2") as HTMLInputElement;
|
||||
@ -53,12 +53,12 @@ describe("Radio", () => {
|
||||
|
||||
it("should change value after click", () => {
|
||||
const {container} = render(
|
||||
<Radio.Group label="Options">
|
||||
<RadioGroup label="Options">
|
||||
<Radio value="1">Option 1</Radio>
|
||||
<Radio className="radio-test-2" value="2">
|
||||
Option 1
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
let radio2 = container
|
||||
@ -73,12 +73,12 @@ describe("Radio", () => {
|
||||
|
||||
it("should ignore events when disabled", () => {
|
||||
const {container} = render(
|
||||
<Radio.Group label="Options">
|
||||
<RadioGroup label="Options">
|
||||
<Radio isDisabled className="radio-test-1" value="1">
|
||||
Option 1
|
||||
</Radio>
|
||||
<Radio value="2">Option 2</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
let radio1 = container
|
||||
@ -93,12 +93,12 @@ describe("Radio", () => {
|
||||
it('should work correctly with "onChange" prop', () => {
|
||||
const onChange = jest.fn();
|
||||
const {container} = render(
|
||||
<Radio.Group label="Options" onChange={onChange}>
|
||||
<RadioGroup label="Options" onChange={onChange}>
|
||||
<Radio value="1">Option 1</Radio>
|
||||
<Radio className="radio-test-2" value="2">
|
||||
Option 2
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
let radio2 = container
|
||||
@ -114,12 +114,12 @@ describe("Radio", () => {
|
||||
it('should work correctly with "onFocus" prop', () => {
|
||||
const onFocus = jest.fn();
|
||||
const {container} = render(
|
||||
<Radio.Group label="Options" onFocus={onFocus}>
|
||||
<RadioGroup label="Options" onFocus={onFocus}>
|
||||
<Radio value="1">Option 1</Radio>
|
||||
<Radio className="radio-test-2" value="2">
|
||||
Option 2
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
let radio2 = container
|
||||
@ -133,12 +133,12 @@ describe("Radio", () => {
|
||||
|
||||
it('should work correctly with "isRequired" prop', () => {
|
||||
const {container} = render(
|
||||
<Radio.Group isRequired label="Options">
|
||||
<RadioGroup isRequired label="Options">
|
||||
<Radio value="1">Option 1</Radio>
|
||||
<Radio className="radio-test-2" value="2">
|
||||
Option 2
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
let radio2 = container
|
||||
@ -155,19 +155,19 @@ describe("Radio", () => {
|
||||
const [value, setValue] = React.useState("1");
|
||||
|
||||
return (
|
||||
<Radio.Group
|
||||
<RadioGroup
|
||||
label="Options"
|
||||
value={value}
|
||||
onChange={(next) => {
|
||||
setValue(next);
|
||||
onChange?.(next);
|
||||
onChange?.(next as any);
|
||||
}}
|
||||
>
|
||||
<Radio value="1">Option 1</Radio>
|
||||
<Radio className="radio-test-2" value="2">
|
||||
Option 2
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
</RadioGroup>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,245 +0,0 @@
|
||||
// import {styled} from "@nextui-org/system";
|
||||
// import {cssFocusVisible} from "@nextui-org/shared-css";
|
||||
|
||||
// export const StyledRadioText = styled("span", {
|
||||
// fontSize: "$$radioSize",
|
||||
// us: "none",
|
||||
// d: "inline-flex",
|
||||
// ai: "center",
|
||||
// variants: {
|
||||
// color: {
|
||||
// default: {
|
||||
// color: "$text",
|
||||
// },
|
||||
// primary: {
|
||||
// color: "$primary",
|
||||
// },
|
||||
// secondary: {
|
||||
// color: "$secondary",
|
||||
// },
|
||||
// success: {
|
||||
// color: "$success",
|
||||
// },
|
||||
// warning: {
|
||||
// color: "$warning",
|
||||
// },
|
||||
// error: {
|
||||
// color: "$error",
|
||||
// },
|
||||
// },
|
||||
// isDisabled: {
|
||||
// true: {
|
||||
// color: "$accents5",
|
||||
// },
|
||||
// },
|
||||
// isInvalid: {
|
||||
// true: {
|
||||
// color: "$error",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
// export const StyledRadioPoint = styled(
|
||||
// "span",
|
||||
// {
|
||||
// size: "$$radioSize",
|
||||
// br: "$$radioRadii",
|
||||
// position: "relative",
|
||||
// d: "inline-block",
|
||||
// mr: "calc($$radioSize * 0.375)",
|
||||
// "&:after": {
|
||||
// content: "",
|
||||
// d: "block",
|
||||
// position: "absolute",
|
||||
// size: "$$radioSize",
|
||||
// br: "$$radioRadii",
|
||||
// boxSizing: "border-box",
|
||||
// border: "2px solid $border",
|
||||
// },
|
||||
// },
|
||||
// cssFocusVisible,
|
||||
// );
|
||||
|
||||
// export const StyledRadio = styled("label", {
|
||||
// d: "flex",
|
||||
// w: "initial",
|
||||
// ai: "flex-start",
|
||||
// position: "relative",
|
||||
// fd: "column",
|
||||
// jc: "flex-start",
|
||||
// cursor: "pointer",
|
||||
// "@motion": {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// transition: "none",
|
||||
// "&:after": {
|
||||
// transition: "none",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// variants: {
|
||||
// color: {
|
||||
// default: {
|
||||
// $$radioColor: "$colors$primary",
|
||||
// $$radioColorHover: "$colors$primarySolidHover",
|
||||
// },
|
||||
// primary: {
|
||||
// $$radioColor: "$colors$primary",
|
||||
// $$radioColorHover: "$colors$primarySolidHover",
|
||||
// },
|
||||
// secondary: {
|
||||
// $$radioColor: "$colors$secondary",
|
||||
// $$radioColorHover: "$colors$secondarySolidHover",
|
||||
// },
|
||||
// success: {
|
||||
// $$radioColor: "$colors$success",
|
||||
// $$radioColorHover: "$colors$successSolidHover",
|
||||
// },
|
||||
// warning: {
|
||||
// $$radioColor: "$colors$warning",
|
||||
// $$radioColorHover: "$colors$warningSolidHover",
|
||||
// },
|
||||
// error: {
|
||||
// $$radioColor: "$colors$error",
|
||||
// $$radioColorHover: "$colors$errorSolidHover",
|
||||
// },
|
||||
// },
|
||||
// size: {
|
||||
// xs: {
|
||||
// $$radioSize: "$space$7",
|
||||
// },
|
||||
// sm: {
|
||||
// $$radioSize: "$space$8",
|
||||
// },
|
||||
// md: {
|
||||
// $$radioSize: "$space$9",
|
||||
// },
|
||||
// lg: {
|
||||
// $$radioSize: "$space$10",
|
||||
// },
|
||||
// xl: {
|
||||
// $$radioSize: "$space$11",
|
||||
// },
|
||||
// },
|
||||
// isHovered: {
|
||||
// true: {},
|
||||
// },
|
||||
// isInvalid: {
|
||||
// true: {
|
||||
// $$radioColor: "$colors$error",
|
||||
// $$radioColorHover: "$colors$errorSolidHover",
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// "&:after": {
|
||||
// borderColor: "$colors$error",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// isDisabled: {
|
||||
// true: {
|
||||
// cursor: "not-allowed",
|
||||
// $$radioColor: "$colors$accents4",
|
||||
// },
|
||||
// },
|
||||
// isSquared: {
|
||||
// true: {
|
||||
// $$radioRadii: "$radii$squared",
|
||||
// },
|
||||
// false: {
|
||||
// $$radioRadii: "$radii$rounded",
|
||||
// },
|
||||
// },
|
||||
// isChecked: {
|
||||
// true: {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// "&:after": {
|
||||
// border: "calc($$radioSize * 0.34) solid $$radioColor",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// disableAnimation: {
|
||||
// true: {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// transition: "none",
|
||||
// "&:after": {
|
||||
// transition: "none",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// false: {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// transition: "$default",
|
||||
// "&:after": {
|
||||
// transition: "$default",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// compoundVariants: [
|
||||
// // isChecked && isHovered
|
||||
// {
|
||||
// isChecked: true,
|
||||
// isHovered: true,
|
||||
// css: {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// "&:after": {
|
||||
// border: "calc($$radioSize * 0.34) solid $$radioColorHover",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// // isChecked && isDisabled & isHovered
|
||||
// {
|
||||
// isChecked: true,
|
||||
// isDisabled: true,
|
||||
// isHovered: true,
|
||||
// css: {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// "&:after": {
|
||||
// border: "calc($$radioSize * 0.34) solid $$radioColor",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// // !isChecked && !isDisabled && isHovered
|
||||
// {
|
||||
// isChecked: false,
|
||||
// isDisabled: false,
|
||||
// isHovered: true,
|
||||
// css: {
|
||||
// [`& ${StyledRadioPoint}`]: {
|
||||
// bg: "$border",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// export const StyledRadioDescription = styled("span", {
|
||||
// color: "$accents7",
|
||||
// fontSize: "calc($$radioSize * 0.85)",
|
||||
// paddingLeft: "calc($$radioSize + $$radioSize * 0.375)",
|
||||
// variants: {
|
||||
// isInvalid: {
|
||||
// true: {
|
||||
// color: "$red500",
|
||||
// },
|
||||
// },
|
||||
// isDisabled: {
|
||||
// true: {
|
||||
// color: "$accents5",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
// export const StyledRadioContainer = styled("div", {
|
||||
// w: "initial",
|
||||
// position: "relative",
|
||||
// d: "flex",
|
||||
// fd: "row",
|
||||
// ai: "center",
|
||||
// jc: "flex-start",
|
||||
// });
|
||||
@ -17,6 +17,7 @@ const Radio = forwardRef<RadioProps, "label">((props, ref) => {
|
||||
getWrapperProps,
|
||||
getInputProps,
|
||||
getLabelProps,
|
||||
getControlProps,
|
||||
} = useRadio({ref, ...props});
|
||||
|
||||
return (
|
||||
@ -25,12 +26,14 @@ const Radio = forwardRef<RadioProps, "label">((props, ref) => {
|
||||
<input {...getInputProps()} />
|
||||
</VisuallyHidden>
|
||||
<span {...getWrapperProps()}>
|
||||
<span className={slots.point({class: styles?.point})} />
|
||||
<span {...getControlProps()} />
|
||||
</span>
|
||||
{children && <span {...getLabelProps()}>{children}</span>}
|
||||
{description && (
|
||||
<span className={slots.description({class: styles?.description})}>{description}</span>
|
||||
)}
|
||||
<div className={slots.labelWrapper({class: styles?.labelWrapper})}>
|
||||
{children && <span {...getLabelProps()}>{children}</span>}
|
||||
{description && (
|
||||
<span className={slots.description({class: styles?.description})}>{description}</span>
|
||||
)}
|
||||
</div>
|
||||
</Component>
|
||||
);
|
||||
});
|
||||
|
||||
@ -69,7 +69,7 @@ export function useRadioGroup(props: UseRadioGroupProps) {
|
||||
isDisabled = false,
|
||||
disableAnimation = false,
|
||||
orientation = "vertical",
|
||||
isRequired,
|
||||
isRequired = false,
|
||||
validationState,
|
||||
className,
|
||||
...otherProps
|
||||
|
||||
@ -36,6 +36,7 @@ interface Props extends HTMLNextUIProps<"label"> {
|
||||
* base:"base-classes",
|
||||
* wrapper: "wrapper-classes",
|
||||
* point: "control-classes", // inner circle
|
||||
* labelWrapper: "label-wrapper-classes", // this wraps the label and description
|
||||
* label: "label-classes",
|
||||
* description: "description-classes",
|
||||
* }} />
|
||||
@ -55,6 +56,8 @@ export function useRadio(props: UseRadioProps) {
|
||||
as,
|
||||
ref,
|
||||
styles,
|
||||
id,
|
||||
value,
|
||||
children,
|
||||
description,
|
||||
size = groupContext?.size ?? "md",
|
||||
@ -71,7 +74,7 @@ export function useRadio(props: UseRadioProps) {
|
||||
if ("checked" in otherProps) {
|
||||
warn('Remove props "checked" if in the Radio.Group.', "Radio");
|
||||
}
|
||||
if (otherProps.value === undefined) {
|
||||
if (value === undefined) {
|
||||
warn('Props "value" must be defined if in the Radio.Group.', "Radio");
|
||||
}
|
||||
}
|
||||
@ -89,7 +92,7 @@ export function useRadio(props: UseRadioProps) {
|
||||
);
|
||||
|
||||
const ariaRadioProps = useMemo(() => {
|
||||
const arialabel =
|
||||
const ariaLabel =
|
||||
otherProps["aria-label"] || typeof children === "string" ? (children as string) : undefined;
|
||||
const ariaDescribedBy =
|
||||
otherProps["aria-describedby"] || typeof description === "string"
|
||||
@ -99,15 +102,16 @@ export function useRadio(props: UseRadioProps) {
|
||||
return {
|
||||
isDisabled,
|
||||
isRequired,
|
||||
"aria-label": arialabel,
|
||||
"aria-labelledby": otherProps["aria-labelledby"] || arialabel,
|
||||
"aria-label": ariaLabel,
|
||||
"aria-describedby": otherProps["aria-describedby"] || ariaDescribedBy,
|
||||
};
|
||||
}, [isDisabled, isRequired]);
|
||||
|
||||
const {inputProps} = useReactAriaRadio(
|
||||
{
|
||||
...otherProps,
|
||||
id,
|
||||
value,
|
||||
children,
|
||||
...groupContext,
|
||||
...ariaRadioProps,
|
||||
},
|
||||
@ -127,11 +131,12 @@ export function useRadio(props: UseRadioProps) {
|
||||
color,
|
||||
size,
|
||||
radius,
|
||||
isInvalid,
|
||||
isDisabled,
|
||||
isFocusVisible,
|
||||
disableAnimation,
|
||||
}),
|
||||
[color, size, radius, isDisabled, isFocusVisible, disableAnimation],
|
||||
[color, size, radius, isDisabled, isInvalid, isFocusVisible, disableAnimation],
|
||||
);
|
||||
|
||||
const baseStyles = clsx(styles?.base, className);
|
||||
@ -151,6 +156,7 @@ export function useRadio(props: UseRadioProps) {
|
||||
return {
|
||||
"data-active": dataAttr(inputProps.checked),
|
||||
"data-hover": dataAttr(isHovered),
|
||||
"data-hover-unchecked": dataAttr(isHovered && !inputProps.checked),
|
||||
"data-checked": dataAttr(inputProps.checked),
|
||||
"data-focus": dataAttr(isFocused),
|
||||
"data-focus-visible": dataAttr(isFocused && isFocusVisible),
|
||||
@ -166,6 +172,9 @@ export function useRadio(props: UseRadioProps) {
|
||||
const getInputProps: PropGetter = () => {
|
||||
return {
|
||||
ref: inputRef,
|
||||
required: isRequired,
|
||||
"aria-required": dataAttr(isRequired),
|
||||
"data-invalid": dataAttr(isInvalid),
|
||||
"data-readonly": dataAttr(inputProps.readOnly),
|
||||
...mergeProps(inputProps, focusProps),
|
||||
};
|
||||
@ -181,6 +190,16 @@ export function useRadio(props: UseRadioProps) {
|
||||
[slots, isDisabled, inputProps.checked, isInvalid],
|
||||
);
|
||||
|
||||
const getControlProps: PropGetter = useCallback(
|
||||
() => ({
|
||||
"data-disabled": dataAttr(isDisabled),
|
||||
"data-checked": dataAttr(inputProps.checked),
|
||||
"data-invalid": dataAttr(isInvalid),
|
||||
className: slots.control({class: styles?.control}),
|
||||
}),
|
||||
[slots, isDisabled, inputProps.checked, isInvalid],
|
||||
);
|
||||
|
||||
return {
|
||||
Component,
|
||||
children,
|
||||
@ -191,6 +210,7 @@ export function useRadio(props: UseRadioProps) {
|
||||
getWrapperProps,
|
||||
getInputProps,
|
||||
getLabelProps,
|
||||
getControlProps,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import {ComponentStory, ComponentMeta} from "@storybook/react";
|
||||
import {radio} from "@nextui-org/theme";
|
||||
import {radio, button} from "@nextui-org/theme";
|
||||
|
||||
import {RadioGroup, Radio, RadioGroupProps} from "../src";
|
||||
|
||||
@ -40,264 +40,121 @@ const defaultProps = {
|
||||
label: "Options",
|
||||
};
|
||||
|
||||
const Template: ComponentStory<typeof RadioGroup> = (args: RadioGroupProps) => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="A">Option A</Radio>
|
||||
<Radio value="B">Option B</Radio>
|
||||
<Radio value="C">Option C</Radio>
|
||||
<Radio value="D">Option D</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
const Template: ComponentStory<typeof RadioGroup> = (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) => {
|
||||
e.preventDefault();
|
||||
alert("Submitted!");
|
||||
}}
|
||||
>
|
||||
<RadioGroup {...args}>{items}</RadioGroup>
|
||||
<button className={button({color: "primary"})} type="submit">
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
) : (
|
||||
<RadioGroup {...args}>{items}</RadioGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
...defaultProps,
|
||||
};
|
||||
|
||||
// import React from "react";
|
||||
// import {Meta} from "@storybook/react";
|
||||
// import {Button} from "@nextui-org/button";
|
||||
// import {Spacer} from "@nextui-org/spacer";
|
||||
export const IsDisabled = Template.bind({});
|
||||
IsDisabled.args = {
|
||||
...defaultProps,
|
||||
isDisabled: true,
|
||||
};
|
||||
|
||||
// import {Radio} from "../src";
|
||||
export const IsRequired = Template.bind({});
|
||||
IsRequired.args = {
|
||||
...defaultProps,
|
||||
isRequired: true,
|
||||
};
|
||||
|
||||
// export default {
|
||||
// title: "Inputs/Radio",
|
||||
// component: Radio,
|
||||
// onChange: {action: "changed"},
|
||||
// } as Meta;
|
||||
export const WithDescription = Template.bind({});
|
||||
WithDescription.args = {
|
||||
...defaultProps,
|
||||
description: "for",
|
||||
};
|
||||
|
||||
// export const Default = () => (
|
||||
// <Radio.Group label="Options">
|
||||
// <Radio value="A">Option A</Radio>
|
||||
// <Radio value="B">Option B</Radio>
|
||||
// <Radio value="C">Option C</Radio>
|
||||
// <Radio value="D">Option D</Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
export const Invalid = Template.bind({});
|
||||
Invalid.args = {
|
||||
...defaultProps,
|
||||
validationState: "invalid",
|
||||
description: "for",
|
||||
};
|
||||
|
||||
// const handleSubmit = (e: any) => {
|
||||
// e.preventDefault();
|
||||
// alert("Submitted!");
|
||||
// };
|
||||
export const Row = Template.bind({});
|
||||
Row.args = {
|
||||
...defaultProps,
|
||||
orientation: "horizontal",
|
||||
description: "for",
|
||||
};
|
||||
|
||||
// export const Required = () => (
|
||||
// <form onSubmit={handleSubmit}>
|
||||
// <Radio.Group isRequired label="Options">
|
||||
// <Radio value="A">Option A</Radio>
|
||||
// <Radio value="B">Option B</Radio>
|
||||
// <Radio value="C">Option C</Radio>
|
||||
// <Radio value="D">Option D</Radio>
|
||||
// </Radio.Group>
|
||||
// <Spacer y={1} />
|
||||
// <Button type="submit">Submit</Button>
|
||||
// </form>
|
||||
// );
|
||||
export const Controlled = () => {
|
||||
const [checked, setChecked] = React.useState<string>("london");
|
||||
|
||||
// export const Disabled = () => (
|
||||
// <Radio.Group isDisabled defaultValue="A" label="Options">
|
||||
// <Radio description="Description for Option A" value="A">
|
||||
// Option A
|
||||
// </Radio>
|
||||
// <Radio value="B">Option B</Radio>
|
||||
// <Radio value="C">Option C</Radio>
|
||||
// <Radio value="D">Option D</Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
React.useEffect(() => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("checked:", checked);
|
||||
}, [checked]);
|
||||
|
||||
// export const Sizes = () => {
|
||||
// return (
|
||||
// <div style={{display: "flex", flexDirection: "row", gap: 200}}>
|
||||
// <Radio.Group defaultValue="md" label="Sizes">
|
||||
// <Radio size="xs" value="xs">
|
||||
// mini
|
||||
// </Radio>
|
||||
// <Radio size="sm" value="sm">
|
||||
// small
|
||||
// </Radio>
|
||||
// <Radio size="md" value="md">
|
||||
// medium
|
||||
// </Radio>
|
||||
// <Radio size="lg" value="lg">
|
||||
// large
|
||||
// </Radio>
|
||||
// <Radio size="xl" value="xl">
|
||||
// xlarge
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// <Radio.Group defaultValue="md" label="Sizes">
|
||||
// <Radio description="Description for Option mini" size="xs" value="xs">
|
||||
// mini
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option small" size="sm" value="sm">
|
||||
// small
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option medium" size="md" value="md">
|
||||
// medium
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option large" size="lg" value="lg">
|
||||
// large
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option xlarge" size="xl" value="xl">
|
||||
// xlarge
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
return (
|
||||
<RadioGroup label="Select city" value={checked} onChange={setChecked}>
|
||||
<Radio value="buenos-aires">Buenos Aires</Radio>
|
||||
<Radio value="sydney">Sydney</Radio>
|
||||
<Radio value="london">London</Radio>
|
||||
<Radio value="tokyo">Tokyo</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
};
|
||||
|
||||
// export const Colors = () => {
|
||||
// return (
|
||||
// <Radio.Group defaultValue="primary" label="Colors">
|
||||
// <Radio color="primary" value="primary">
|
||||
// primary
|
||||
// </Radio>
|
||||
// <Radio color="secondary" value="secondary">
|
||||
// secondary
|
||||
// </Radio>
|
||||
// <Radio color="success" value="success">
|
||||
// success
|
||||
// </Radio>
|
||||
// <Radio color="warning" value="warning">
|
||||
// warning
|
||||
// </Radio>
|
||||
// <Radio color="error" value="error">
|
||||
// error
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export const LabelColors = () => {
|
||||
// return (
|
||||
// <Radio.Group defaultValue="primary" label="Label colors">
|
||||
// <Radio color="primary" labelColor="primary" value="primary">
|
||||
// primary
|
||||
// </Radio>
|
||||
// <Radio color="secondary" labelColor="secondary" value="secondary">
|
||||
// secondary
|
||||
// </Radio>
|
||||
// <Radio color="success" labelColor="success" value="success">
|
||||
// success
|
||||
// </Radio>
|
||||
// <Radio color="warning" labelColor="warning" value="warning">
|
||||
// warning
|
||||
// </Radio>
|
||||
// <Radio color="error" labelColor="error" value="error">
|
||||
// error
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export const Squared = () => (
|
||||
// <Radio.Group defaultValue="A" label="Options">
|
||||
// <Radio isSquared value="A">
|
||||
// Option A
|
||||
// </Radio>
|
||||
// <Radio isSquared value="B">
|
||||
// Option B
|
||||
// </Radio>
|
||||
// <Radio isSquared value="C">
|
||||
// Option C
|
||||
// </Radio>
|
||||
// <Radio isSquared value="D">
|
||||
// Option D
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
|
||||
// export const Description = () => (
|
||||
// <Radio.Group defaultValue="A" label="Options">
|
||||
// <Radio description="Description for Option A" value="A">
|
||||
// Option A
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option B" value="B">
|
||||
// Option B
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option C" value="C">
|
||||
// Option C
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option D" value="D">
|
||||
// Option D
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
|
||||
// export const Invalid = () => (
|
||||
// <Radio.Group defaultValue="A" label="Options" validationState="invalid">
|
||||
// <Radio description="Description for Option A" value="A">
|
||||
// Option A
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option B" value="B">
|
||||
// Option B
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option C" value="C">
|
||||
// Option C
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option D" value="D">
|
||||
// Option D
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
|
||||
// export const Row = () => (
|
||||
// <div style={{display: "flex", flexDirection: "column", gap: 100}}>
|
||||
// <Radio.Group defaultValue="A" label="Options" orientation="horizontal">
|
||||
// <Radio value="A">Option A</Radio>
|
||||
// <Radio value="B">Option B</Radio>
|
||||
// <Radio value="C">Option C</Radio>
|
||||
// <Radio value="D">Option D</Radio>
|
||||
// </Radio.Group>
|
||||
// <Radio.Group defaultValue="A" label="Options" orientation="horizontal">
|
||||
// <Radio description="Description for Option A" value="A">
|
||||
// Option A
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option B" value="B">
|
||||
// Option B
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option C" value="C">
|
||||
// Option C
|
||||
// </Radio>
|
||||
// <Radio description="Description for Option D" value="D">
|
||||
// Option D
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// </div>
|
||||
// );
|
||||
|
||||
// export const Controlled = () => {
|
||||
// const [checked, setChecked] = React.useState<string>("london");
|
||||
|
||||
// React.useEffect(() => {
|
||||
// console.log("checked:", checked);
|
||||
// }, [checked]);
|
||||
|
||||
// return (
|
||||
// <Radio.Group label="Check cities" value={checked} onChange={(value) => setChecked(value)}>
|
||||
// <Radio value="buenos-aires">Buenos Aires</Radio>
|
||||
// <Radio value="sydney">Sydney</Radio>
|
||||
// <Radio value="london">London</Radio>
|
||||
// <Radio value="tokyo">Tokyo</Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export const DisableAnimation = () => {
|
||||
// return (
|
||||
// <Radio.Group defaultValue="A" label="Options">
|
||||
// <Radio disableAnimation value="A">
|
||||
// Option A
|
||||
// </Radio>
|
||||
// <Radio disableAnimation value="B">
|
||||
// Option B
|
||||
// </Radio>
|
||||
// <Radio disableAnimation value="C">
|
||||
// Option C
|
||||
// </Radio>
|
||||
// <Radio disableAnimation value="D">
|
||||
// Option D
|
||||
// </Radio>
|
||||
// </Radio.Group>
|
||||
// );
|
||||
// };
|
||||
export const DisableAnimation = Template.bind({});
|
||||
DisableAnimation.args = {
|
||||
...defaultProps,
|
||||
disableAnimation: true,
|
||||
};
|
||||
|
||||
1
packages/core/theme/config.d.ts
vendored
1
packages/core/theme/config.d.ts
vendored
@ -1 +0,0 @@
|
||||
export * from "./dist/config";
|
||||
@ -1 +0,0 @@
|
||||
module.exports = require("./dist/config");
|
||||
@ -46,8 +46,8 @@ const checkbox = tv({
|
||||
"data-[checked=true]:after:scale-100",
|
||||
"data-[checked=true]:after:opacity-100",
|
||||
// hover
|
||||
"hover:before:bg-neutral",
|
||||
"data-[hover=true]:before:bg-neutral",
|
||||
"hover:before:bg-neutral-100",
|
||||
"data-[hover=true]:before:bg-neutral-100",
|
||||
],
|
||||
icon: "z-10 w-4 h-3 opacity-0 data-[checked=true]:opacity-100",
|
||||
label: "relative ml-1 text-foreground select-none",
|
||||
@ -154,8 +154,7 @@ const checkbox = tv({
|
||||
wrapper: "transition-none",
|
||||
},
|
||||
false: {
|
||||
wrapper:
|
||||
"before:transition-background after:transition-transform-opacity before:!duration-250 after:!duration-250",
|
||||
wrapper: ["before:transition-background", "after:transition-transform-opacity"],
|
||||
icon: "transition-opacity",
|
||||
label: "transition-opacity before:transition-width",
|
||||
},
|
||||
|
||||
@ -5,56 +5,157 @@ import {ringClasses} from "../utils";
|
||||
/**
|
||||
* Radio wrapper **Tailwind Variants** component
|
||||
*
|
||||
* const {base, wrapper, point, label, description} = radio({...})
|
||||
* const {base, wrapper, point, labelWrapper, label, description} = radio({...})
|
||||
*
|
||||
* @example
|
||||
* <label className={base())}>
|
||||
* // input
|
||||
* <span className={wrapper()} aria-hidden="true" data-checked={checked}>
|
||||
* <span className={wrapper()} aria-hidden="true" data-checked={checked} data-hover-unchecked={hoverUnchecked}>
|
||||
* <span className={point()}/>
|
||||
* </span>
|
||||
* <span className={label()}>Label</span>
|
||||
* <span className={description()}>Description</span>
|
||||
* <div className={labelWrapper()}>
|
||||
* <span className={label()}>Label</span>
|
||||
* <span className={description()}>Description</span>
|
||||
* </div>
|
||||
* </label>
|
||||
*/
|
||||
const radio = tv({
|
||||
slots: {
|
||||
base: "relative max-w-fit inline-flex items-center justify-start cursor-pointer",
|
||||
wrapper: "",
|
||||
point: "",
|
||||
label: "relative ml-1 text-foreground select-none",
|
||||
description: "relative ml-1 text-neutral-500 select-none",
|
||||
wrapper: [
|
||||
"relative",
|
||||
"inline-flex",
|
||||
"items-center",
|
||||
"justify-center",
|
||||
"flex-shrink-0",
|
||||
"overflow-hidden",
|
||||
"border-solid",
|
||||
"border-2",
|
||||
"box-border",
|
||||
"border-neutral",
|
||||
"data-[hover-unchecked=true]:bg-neutral-100",
|
||||
],
|
||||
labelWrapper: "flex flex-col ml-1",
|
||||
control: [
|
||||
"z-10",
|
||||
"w-2",
|
||||
"h-2",
|
||||
"opacity-0",
|
||||
"scale-0",
|
||||
"origin-center",
|
||||
"data-[checked=true]:opacity-100",
|
||||
"data-[checked=true]:scale-100",
|
||||
],
|
||||
label: "relative text-foreground select-none",
|
||||
description: "relative text-neutral-400",
|
||||
},
|
||||
variants: {
|
||||
color: {
|
||||
neutral: {},
|
||||
primary: {},
|
||||
secondary: {},
|
||||
success: {},
|
||||
warning: {},
|
||||
danger: {},
|
||||
neutral: {
|
||||
control: "bg-neutral-500 text-neutral-contrastText",
|
||||
wrapper: "data-[checked=true]:border-neutral-500",
|
||||
},
|
||||
primary: {
|
||||
control: "bg-primary text-primary-contrastText",
|
||||
wrapper: "data-[checked=true]:border-primary",
|
||||
},
|
||||
secondary: {
|
||||
control: "bg-secondary text-secondary-contrastText",
|
||||
wrapper: "data-[checked=true]:border-secondary",
|
||||
},
|
||||
success: {
|
||||
control: "bg-success text-success-contrastText",
|
||||
wrapper: "data-[checked=true]:border-success",
|
||||
},
|
||||
warning: {
|
||||
control: "bg-warning text-warning-contrastText",
|
||||
wrapper: "data-[checked=true]:border-warning",
|
||||
},
|
||||
danger: {
|
||||
control: "bg-danger text-danger-contrastText",
|
||||
wrapper: "data-[checked=true]:border-danger",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
xs: {},
|
||||
sm: {},
|
||||
md: {},
|
||||
lg: {},
|
||||
xl: {},
|
||||
xs: {
|
||||
wrapper: "w-3.5 h-3.5",
|
||||
control: "w-1 h-1",
|
||||
labelWrapper: "ml-1",
|
||||
label: "text-xs",
|
||||
description: "text-xs",
|
||||
},
|
||||
sm: {
|
||||
wrapper: "w-4 h-4",
|
||||
control: "w-1.5 h-1.5",
|
||||
labelWrapper: "ml-1",
|
||||
label: "text-sm",
|
||||
description: "text-xs",
|
||||
},
|
||||
md: {
|
||||
wrapper: "w-5 h-5",
|
||||
control: "w-2 h-2",
|
||||
labelWrapper: "ml-2",
|
||||
label: "text-base",
|
||||
description: "text-sm",
|
||||
},
|
||||
lg: {
|
||||
wrapper: "w-6 h-6",
|
||||
control: "w-2.5 h-2.5",
|
||||
labelWrapper: "ml-2",
|
||||
label: "text-lg",
|
||||
description: "text-base",
|
||||
},
|
||||
xl: {
|
||||
wrapper: "w-7 h-7",
|
||||
control: "w-3 h-3",
|
||||
labelWrapper: "ml-3",
|
||||
label: "text-xl",
|
||||
description: "text-lg",
|
||||
},
|
||||
},
|
||||
radius: {
|
||||
none: {},
|
||||
base: {},
|
||||
sm: {},
|
||||
md: {},
|
||||
lg: {},
|
||||
xl: {},
|
||||
full: {},
|
||||
none: {
|
||||
wrapper: "rounded-none",
|
||||
control: "rounded-none",
|
||||
},
|
||||
base: {
|
||||
wrapper: "rounded",
|
||||
control: "rounded",
|
||||
},
|
||||
sm: {
|
||||
wrapper: "rounded-sm",
|
||||
control: "rounded-sm",
|
||||
},
|
||||
md: {
|
||||
wrapper: "rounded-md",
|
||||
control: "rounded-sm",
|
||||
},
|
||||
lg: {
|
||||
wrapper: "rounded-lg",
|
||||
control: "rounded",
|
||||
},
|
||||
xl: {
|
||||
wrapper: "rounded-xl",
|
||||
control: "rounded-md",
|
||||
},
|
||||
full: {
|
||||
wrapper: "rounded-full",
|
||||
control: "rounded-full",
|
||||
},
|
||||
},
|
||||
isDisabled: {
|
||||
true: {
|
||||
base: "opacity-50 pointer-events-none",
|
||||
},
|
||||
},
|
||||
isInvalid: {
|
||||
true: {
|
||||
control: "bg-danger text-danger-contrastText",
|
||||
wrapper: "border-danger data-[checked=true]:border-danger",
|
||||
label: "text-danger",
|
||||
description: "text-danger-300",
|
||||
},
|
||||
},
|
||||
isFocusVisible: {
|
||||
true: {
|
||||
wrapper: [...ringClasses],
|
||||
@ -62,14 +163,18 @@ const radio = tv({
|
||||
},
|
||||
disableAnimation: {
|
||||
true: {},
|
||||
false: {},
|
||||
false: {
|
||||
wrapper: "transition-background",
|
||||
control: "transition-transform-opacity",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
color: "primary",
|
||||
size: "md",
|
||||
radius: "md",
|
||||
radius: "full",
|
||||
isDisabled: false,
|
||||
isInvalid: false,
|
||||
disableAnimation: false,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
import type {Config as TWConfig} from "tailwindcss/types/config";
|
||||
|
||||
import get from "lodash.get";
|
||||
import deepMerge from "deepmerge";
|
||||
import resolveConfig from "tailwindcss/resolveConfig";
|
||||
|
||||
import {commonColors} from "./colors";
|
||||
// import {theme} from "./plugin";
|
||||
|
||||
export type NextUIDefaultColors = {
|
||||
background: string;
|
||||
foreground: string;
|
||||
border: string;
|
||||
neutral: string;
|
||||
primary: string;
|
||||
secondary: string;
|
||||
success: string;
|
||||
danger: string;
|
||||
warning: string;
|
||||
};
|
||||
|
||||
export type ColorValue =
|
||||
| NextUIDefaultColors
|
||||
| Record<string, string>
|
||||
| Record<string, Record<number, string>>;
|
||||
|
||||
export type Colors = {
|
||||
common?: ColorValue;
|
||||
light?: ColorValue;
|
||||
dark?: ColorValue;
|
||||
};
|
||||
|
||||
export type ExtendedThemeConfig = TWConfig["theme"] & {
|
||||
extend?: Omit<TWConfig["theme"], "extend"> & {
|
||||
colors?: Colors;
|
||||
};
|
||||
};
|
||||
|
||||
export interface Config extends TWConfig {
|
||||
theme?: ExtendedThemeConfig;
|
||||
}
|
||||
|
||||
export type WithNextUI = {
|
||||
<C extends Config>(nextuiConfig: Config): C;
|
||||
};
|
||||
|
||||
export const withNextUI = (tailwindConfig: Config) => {
|
||||
let config = resolveConfig(tailwindConfig);
|
||||
|
||||
const userColors = get(config.theme, "colors", {});
|
||||
// const userLightColors = get(userColors, "light", {});
|
||||
// const userDarkColors = get(userColors, "dark", {});
|
||||
|
||||
if (userColors && config.theme?.colors) {
|
||||
config.theme.colors = deepMerge(userColors, commonColors);
|
||||
}
|
||||
|
||||
// config.plugins = [
|
||||
// theme({
|
||||
// light: {
|
||||
// primary: "#0072f5",
|
||||
// secondary: "darkblue",
|
||||
// brand: "#F3F3F3",
|
||||
// },
|
||||
// dark: {
|
||||
// primary: "#17c964",
|
||||
// secondary: "tomato",
|
||||
// brand: "#4A4A4A",
|
||||
// },
|
||||
// }),
|
||||
// theme({
|
||||
// light: deepMerge(semanticColors.light, userLightColors),
|
||||
// dark: deepMerge(semanticColors.dark, userDarkColors),
|
||||
// }),
|
||||
// ];
|
||||
|
||||
// console.log(config);
|
||||
|
||||
return config;
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
const DEFAULT_TRANSITION_DURATION = "200ms";
|
||||
const DEFAULT_TRANSITION_DURATION = "250ms";
|
||||
|
||||
export const utilities = {
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user