mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(components): radio component added, tests still missing
This commit is contained in:
parent
1808f51ebb
commit
733e1399dd
@ -105,9 +105,9 @@ function CodeTypewriter({value, className, css, ...props}: any) {
|
||||
return (
|
||||
<Pre className={className} css={css} {...props}>
|
||||
<code
|
||||
dangerouslySetInnerHTML={{__html: value}}
|
||||
ref={wrapperRef}
|
||||
className={className}
|
||||
dangerouslySetInnerHTML={{__html: value}}
|
||||
style={{opacity: 0}}
|
||||
/>
|
||||
</Pre>
|
||||
@ -136,7 +136,7 @@ const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forw
|
||||
// convert to html
|
||||
result = hastToHtml(result);
|
||||
|
||||
// TODO reset theme
|
||||
// TODO: reset theme
|
||||
|
||||
const classes = `language-${language} ${className}`;
|
||||
|
||||
@ -153,7 +153,7 @@ const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forw
|
||||
{...props}
|
||||
>
|
||||
{showWindowIcons && <WindowActions />}
|
||||
<code className={classes} dangerouslySetInnerHTML={{__html: result}} />
|
||||
<code dangerouslySetInnerHTML={{__html: result}} className={classes} />
|
||||
</Pre>
|
||||
);
|
||||
});
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
"@babel/cli": "^7.14.5",
|
||||
"@babel/core": "^7.16.7",
|
||||
"@react-types/link": "^3.3.3",
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/shared": "^3.15.0",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.15.6",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
"@nextui-org/grid": "workspace:*",
|
||||
"@nextui-org/loading": "workspace:*",
|
||||
"@nextui-org/shared-icons": "workspace:*",
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/shared": "^3.15.0",
|
||||
"@react-types/button": "^3.6.2",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
|
||||
@ -10,7 +10,7 @@ import {mergeProps} from "@react-aria/utils";
|
||||
import {useDrip} from "@nextui-org/drip";
|
||||
import {useHover} from "@react-aria/interactions";
|
||||
import {IFocusRingAria, useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {__DEV__} from "@nextui-org/shared-utils";
|
||||
import {__DEV__, warn} from "@nextui-org/shared-utils";
|
||||
|
||||
import {getColors} from "./button-utils";
|
||||
import {useButtonGroupContext} from "./button-group-context";
|
||||
@ -157,7 +157,7 @@ export function useButton(props: UseButtonProps) {
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
if (__DEV__ && color === "gradient" && (flat || light)) {
|
||||
console.warn("Using the gradient color on flat and light buttons will have no effect.");
|
||||
warn("Using the gradient color on flat and light buttons will have no effect.", "Button");
|
||||
}
|
||||
|
||||
const buttonProps = {
|
||||
@ -193,7 +193,7 @@ export function useButton(props: UseButtonProps) {
|
||||
}
|
||||
if (deprecatedOnClick) {
|
||||
deprecatedOnClick(e as any);
|
||||
console.warn("onClick is deprecated, please use onPress");
|
||||
warn("onClick is deprecated, please use onPress", "Button");
|
||||
}
|
||||
onPress?.(e);
|
||||
};
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
"@react-aria/interactions": "^3.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/shared": "^3.15.0",
|
||||
"@nextui-org/text": "workspace:*",
|
||||
"@nextui-org/grid": "workspace:*",
|
||||
"@nextui-org/col": "workspace:*",
|
||||
|
||||
@ -5,7 +5,7 @@ import {mergeProps} from "@react-aria/utils";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
import {usePress, useHover} from "@react-aria/interactions";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {NormalWeights, ReactRef} from "@nextui-org/shared-utils";
|
||||
import {NormalWeights, ReactRef, warn} from "@nextui-org/shared-utils";
|
||||
import {useDOMRef, IFocusRingAria} from "@nextui-org/dom-utils";
|
||||
import {useDrip} from "@nextui-org/drip";
|
||||
|
||||
@ -89,7 +89,7 @@ export function useCard(props: UseCardProps) {
|
||||
}
|
||||
if (deprecatedOnClick) {
|
||||
deprecatedOnClick(e as any);
|
||||
console.warn("onClick is deprecated, please use onPress");
|
||||
warn("onClick is deprecated, please use onPress", "Card");
|
||||
}
|
||||
onPress?.(e);
|
||||
};
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-types/checkbox": "^3.4.0",
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/shared": "^3.15.0",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {StyledCheckboxLabel} from "./checkbox.styles";
|
||||
import {StyledCheckbox} from "./checkbox.styles";
|
||||
|
||||
export const StyledCheckboxGroupContainer = styled("div", {
|
||||
display: "flex",
|
||||
@ -10,14 +10,14 @@ export const StyledCheckboxGroupContainer = styled("div", {
|
||||
true: {
|
||||
flexDirection: "row",
|
||||
mt: 0,
|
||||
[`& ${StyledCheckboxLabel}`]: {
|
||||
[`& ${StyledCheckbox}`]: {
|
||||
mr: "$$checkboxSize",
|
||||
},
|
||||
},
|
||||
false: {
|
||||
mr: 0,
|
||||
flexDirection: "column",
|
||||
[`& ${StyledCheckboxLabel}:not(:first-child)`]: {
|
||||
[`& ${StyledCheckbox}:not(:first-child)`]: {
|
||||
mt: "$$checkboxSize",
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
import {cssFocusVisible} from "@nextui-org/shared-css";
|
||||
|
||||
export const StyledCheckboxLabel = styled("label", {
|
||||
export const StyledCheckbox = styled("label", {
|
||||
$$checkboxBorderColor: "$colors$border",
|
||||
$$checkboxBorderRadius: "$radii$squared",
|
||||
d: "inline-flex",
|
||||
|
||||
@ -5,7 +5,7 @@ import {mergeProps} from "@react-aria/utils";
|
||||
import {VisuallyHidden} from "@react-aria/visually-hidden";
|
||||
|
||||
import {
|
||||
StyledCheckboxLabel,
|
||||
StyledCheckbox,
|
||||
StyledCheckboxContainer,
|
||||
StyledCheckboxMask,
|
||||
StyledCheckboxText,
|
||||
@ -48,7 +48,7 @@ const Checkbox = forwardRef<CheckboxProps, "label", CompoundCheckbox>((props, re
|
||||
const domRef = useFocusableRef(ref, inputRef);
|
||||
|
||||
return (
|
||||
<StyledCheckboxLabel
|
||||
<StyledCheckbox
|
||||
ref={domRef}
|
||||
as={as}
|
||||
className={clsx("nextui-checkbox", className)}
|
||||
@ -117,7 +117,7 @@ const Checkbox = forwardRef<CheckboxProps, "label", CompoundCheckbox>((props, re
|
||||
{children || label}
|
||||
</StyledCheckboxText>
|
||||
)}
|
||||
</StyledCheckboxLabel>
|
||||
</StyledCheckbox>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
|
||||
|
||||
const {labelProps, groupProps} = useReactAriaCheckboxGroup(otherProps, groupState);
|
||||
|
||||
const context = {
|
||||
const context: ContextType = {
|
||||
size,
|
||||
color,
|
||||
labelColor,
|
||||
|
||||
@ -6,7 +6,7 @@ import {useMemo, useRef} from "react";
|
||||
import {useToggleState} from "@react-stately/toggle";
|
||||
import {useHover, usePress} from "@react-aria/interactions";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
import {NormalSizes, NormalColors, SimpleColors, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {NormalSizes, NormalColors, SimpleColors, __DEV__, warn} from "@nextui-org/shared-utils";
|
||||
import {
|
||||
useCheckbox as useReactAriaCheckbox,
|
||||
useCheckboxGroupItem as useReactAriaCheckboxGroupItem,
|
||||
@ -76,16 +76,17 @@ export function useCheckbox(props: UseCheckboxProps) {
|
||||
} = props;
|
||||
|
||||
if (groupContext && __DEV__) {
|
||||
const warningMessage =
|
||||
"The Checkbox.Group is being used, `%s` will be ignored. Use the `%s` of the Checkbox.Group instead.";
|
||||
|
||||
if (isSelected) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(warningMessage, "isSelected", "value");
|
||||
warn(
|
||||
"The Checkbox.Group is being used, `isSelected` will be ignored. Use the `value` of the Checkbox.Group instead.",
|
||||
"Checkbox",
|
||||
);
|
||||
}
|
||||
if (defaultSelected) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(warningMessage, "defaultSelected", "defaultValue");
|
||||
warn(
|
||||
"The Checkbox.Group is being used, `defaultSelected` will be ignored. Use the `defaultValue` of the Checkbox.Group instead.",
|
||||
"Checkbox",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import {HTMLNextUIProps, CSS, getTokenValue} from "@nextui-org/system";
|
||||
import {IFocusRingAria} from "@nextui-org/dom-utils";
|
||||
import {isNormalColor} from "@nextui-org//shared-utils";
|
||||
|
||||
export interface UseLinkProps extends HTMLNextUIProps<"a", AriaLinkProps> {
|
||||
export interface Props extends HTMLNextUIProps<"a"> {
|
||||
/**
|
||||
* The link's color.
|
||||
* @default "$colors$link"
|
||||
@ -33,6 +33,8 @@ export interface UseLinkProps extends HTMLNextUIProps<"a", AriaLinkProps> {
|
||||
isExternal?: boolean;
|
||||
}
|
||||
|
||||
export type UseLinkProps = Props & AriaLinkProps;
|
||||
|
||||
export function useLink(props: UseLinkProps) {
|
||||
const {
|
||||
isExternal = false,
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"],
|
||||
"@react-types/link": ["../../../node_modules/@react-types/link"],
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"]
|
||||
}
|
||||
},
|
||||
"include": ["src", "index.ts"]
|
||||
|
||||
24
packages/components/radio/README.md
Normal file
24
packages/components/radio/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/radio
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/radio
|
||||
# or
|
||||
npm i @nextui-org/radio
|
||||
```
|
||||
|
||||
## Contribution
|
||||
|
||||
Yes please! See the
|
||||
[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md)
|
||||
for details.
|
||||
|
||||
## Licence
|
||||
|
||||
This project is licensed under the terms of the
|
||||
[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE).
|
||||
29
packages/components/radio/__tests__/radio.test.tsx
Normal file
29
packages/components/radio/__tests__/radio.test.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
|
||||
import {Radio} from "../src";
|
||||
|
||||
describe("Radio", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(
|
||||
<Radio.Group label="Options">
|
||||
<Radio value="1">Option 1</Radio>
|
||||
</Radio.Group>,
|
||||
);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLLabelElement>();
|
||||
|
||||
render(
|
||||
<Radio.Group label="Options">
|
||||
<Radio ref={ref} value="1">
|
||||
Option 1
|
||||
</Radio>
|
||||
</Radio.Group>,
|
||||
);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
});
|
||||
3
packages/components/radio/clean-package.config.json
Normal file
3
packages/components/radio/clean-package.config.json
Normal file
@ -0,0 +1,3 @@
|
||||
{ "replace": { "main": "dist/index.cjs.js", "module": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts", "exports": { ".": { "import": "./dist/index.esm.js",
|
||||
"require": "./dist/index.cjs.js" }, "./package.json": "./package.json" } } }
|
||||
59
packages/components/radio/package.json
Normal file
59
packages/components/radio/package.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@nextui-org/radio",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Radios allow users to select a single option from a list of mutually exclusive options.",
|
||||
"keywords": [
|
||||
"radio"
|
||||
],
|
||||
"author": "Junior Garcia <jrgarciadev@gmail.com>",
|
||||
"homepage": "https://nextui.org",
|
||||
"license": "MIT",
|
||||
"main": "src/index.ts",
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nextui-org/nextui.git",
|
||||
"directory": "packages/components/radio"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextui-org/nextui/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format=esm,cjs --dts",
|
||||
"dev": "yarn build:fast -- --watch",
|
||||
"clean": "rimraf dist .turbo",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build:fast": "tsup src/index.ts --format=esm,cjs",
|
||||
"prepack": "clean-package",
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/dom-utils": "workspace:*",
|
||||
"@nextui-org/shared-css": "workspace:*",
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@react-aria/focus": "^3.9.0",
|
||||
"@react-aria/interactions": "^3.12.0",
|
||||
"@react-aria/radio": "^3.4.0",
|
||||
"@react-aria/utils": "^3.14.0",
|
||||
"@react-aria/visually-hidden": "^3.5.0",
|
||||
"@react-stately/radio": "^3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-types/radio": "^3.3.0",
|
||||
"@react-types/shared": "^3.15.0",
|
||||
"@nextui-org/button": "workspace:*",
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
5
packages/components/radio/src/index.ts
Normal file
5
packages/components/radio/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// export types
|
||||
export type {RadioProps} from "./radio";
|
||||
|
||||
// export component
|
||||
export {default as Radio} from "./radio";
|
||||
10
packages/components/radio/src/radio-group-context.ts
Normal file
10
packages/components/radio/src/radio-group-context.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type {ContextType} from "./use-radio-group";
|
||||
|
||||
import {createContext} from "@nextui-org/shared-utils";
|
||||
|
||||
export const [RadioGroupProvider, useRadioGroupContext] = createContext<ContextType>({
|
||||
name: "RadioGroupContext",
|
||||
strict: true,
|
||||
errorMessage:
|
||||
"useRadioGroupContext: `context` is undefined. Seems you forgot to wrap all checkbox components within `<Radio.Group />`",
|
||||
});
|
||||
61
packages/components/radio/src/radio-group.styles.ts
Normal file
61
packages/components/radio/src/radio-group.styles.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {StyledRadio} from "./radio.styles";
|
||||
|
||||
export const StyledRadioGroupContainer = styled("div", {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
variants: {
|
||||
isRow: {
|
||||
true: {
|
||||
mt: 0,
|
||||
flexDirection: "row",
|
||||
[`& ${StyledRadio}:not(:last-child)`]: {
|
||||
mr: "$$radioSize",
|
||||
},
|
||||
},
|
||||
false: {
|
||||
mr: 0,
|
||||
flexDirection: "column",
|
||||
[`& ${StyledRadio}:not(:first-child)`]: {
|
||||
mt: "$$radioSize",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledRadioGroup = styled("div", {
|
||||
border: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
display: "flex",
|
||||
fd: "column",
|
||||
variants: {
|
||||
size: {
|
||||
xs: {
|
||||
$$radioGroupGap: "$space$7",
|
||||
},
|
||||
sm: {
|
||||
$$radioGroupGap: "$space$8",
|
||||
},
|
||||
md: {
|
||||
$$radioGroupGap: "$space$9",
|
||||
},
|
||||
lg: {
|
||||
$$radioGroupGap: "$space$10",
|
||||
},
|
||||
xl: {
|
||||
$$radioGroupGap: "$space$11",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledRadioGroupLabel = styled("label", {
|
||||
d: "block",
|
||||
fontWeight: "$normal",
|
||||
fontSize: "calc($$checkboxSize * 0.9)",
|
||||
color: "$accents8",
|
||||
mb: "$3",
|
||||
});
|
||||
50
packages/components/radio/src/radio-group.tsx
Normal file
50
packages/components/radio/src/radio-group.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
|
||||
import {RadioGroupProvider} from "./radio-group-context";
|
||||
import {
|
||||
StyledRadioGroup,
|
||||
StyledRadioGroupLabel,
|
||||
StyledRadioGroupContainer,
|
||||
} from "./radio-group.styles";
|
||||
import {UseRadioGroupProps, useRadioGroup} from "./use-radio-group";
|
||||
|
||||
export interface RadioGroupProps extends UseRadioGroupProps {}
|
||||
|
||||
const RadioGroup = forwardRef<RadioGroupProps, "div">((props, ref) => {
|
||||
const {className, children, orientation, label, context, groupProps, labelProps, ...otherProps} =
|
||||
useRadioGroup(props);
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
return (
|
||||
<StyledRadioGroup
|
||||
ref={domRef}
|
||||
className={clsx("nextui-radio-group", className)}
|
||||
{...mergeProps(groupProps, otherProps)}
|
||||
>
|
||||
{label && (
|
||||
<StyledRadioGroupLabel className="nextui-radio-group-label" {...labelProps}>
|
||||
{label}
|
||||
</StyledRadioGroupLabel>
|
||||
)}
|
||||
<StyledRadioGroupContainer
|
||||
className="nextui-radio-group-items"
|
||||
isRow={orientation === "horizontal"}
|
||||
role="presentation"
|
||||
>
|
||||
<RadioGroupProvider value={context}>{children}</RadioGroupProvider>
|
||||
</StyledRadioGroupContainer>
|
||||
</StyledRadioGroup>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
RadioGroup.displayName = "NextUI.RadioGroup";
|
||||
}
|
||||
|
||||
RadioGroup.toString = () => ".nextui-radio-group";
|
||||
|
||||
export default RadioGroup;
|
||||
245
packages/components/radio/src/radio.styles.ts
Normal file
245
packages/components/radio/src/radio.styles.ts
Normal file
@ -0,0 +1,245 @@
|
||||
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",
|
||||
});
|
||||
109
packages/components/radio/src/radio.tsx
Normal file
109
packages/components/radio/src/radio.tsx
Normal file
@ -0,0 +1,109 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {useFocusableRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {VisuallyHidden} from "@react-aria/visually-hidden";
|
||||
|
||||
import RadioGroup from "./radio-group";
|
||||
import {
|
||||
StyledRadio,
|
||||
StyledRadioContainer,
|
||||
StyledRadioPoint,
|
||||
StyledRadioText,
|
||||
StyledRadioDescription,
|
||||
} from "./radio.styles";
|
||||
import {UseRadioProps, useRadio} from "./use-radio";
|
||||
|
||||
export interface RadioProps extends UseRadioProps {}
|
||||
|
||||
type CompoundRadio = {
|
||||
Group: typeof RadioGroup;
|
||||
};
|
||||
|
||||
const Radio = forwardRef<RadioProps, "label", CompoundRadio>((props, ref) => {
|
||||
const {className, as, css, children, label, description, ...radioProps} = props;
|
||||
|
||||
const {
|
||||
size,
|
||||
state,
|
||||
color,
|
||||
inputRef,
|
||||
labelColor,
|
||||
isHovered,
|
||||
isSquared,
|
||||
isInvalid,
|
||||
isDisabled,
|
||||
disableAnimation,
|
||||
isFocusVisible,
|
||||
focusProps,
|
||||
hoverProps,
|
||||
inputProps,
|
||||
isRequired,
|
||||
...otherProps
|
||||
} = useRadio({...radioProps, children: children ?? label});
|
||||
|
||||
const domRef = useFocusableRef(ref, inputRef);
|
||||
|
||||
return (
|
||||
<StyledRadio
|
||||
ref={domRef}
|
||||
{...mergeProps(hoverProps, otherProps)}
|
||||
as={as}
|
||||
className={clsx("nextui-radio", className)}
|
||||
color={color}
|
||||
css={css}
|
||||
data-state={state}
|
||||
disableAnimation={disableAnimation}
|
||||
isChecked={inputProps.checked}
|
||||
isDisabled={isDisabled}
|
||||
isHovered={isHovered}
|
||||
isInvalid={isInvalid}
|
||||
isSquared={isSquared}
|
||||
size={size}
|
||||
>
|
||||
<StyledRadioContainer className="nextui-radio-container">
|
||||
<StyledRadioPoint
|
||||
className="nextui-radio-point"
|
||||
isFocusVisible={isFocusVisible}
|
||||
{...focusProps}
|
||||
>
|
||||
<VisuallyHidden>
|
||||
<input
|
||||
ref={inputRef}
|
||||
className="nextui-radio-input"
|
||||
required={isRequired}
|
||||
{...mergeProps(inputProps, focusProps)}
|
||||
/>
|
||||
</VisuallyHidden>
|
||||
</StyledRadioPoint>
|
||||
<StyledRadioText
|
||||
className="nextui-radio-label"
|
||||
color={labelColor}
|
||||
isDisabled={isDisabled}
|
||||
isInvalid={isInvalid}
|
||||
>
|
||||
{children}
|
||||
</StyledRadioText>
|
||||
</StyledRadioContainer>
|
||||
{description && (
|
||||
<StyledRadioDescription
|
||||
className="nextui-radio-description"
|
||||
isDisabled={isDisabled}
|
||||
isInvalid={isInvalid}
|
||||
>
|
||||
{description}
|
||||
</StyledRadioDescription>
|
||||
)}
|
||||
</StyledRadio>
|
||||
);
|
||||
});
|
||||
|
||||
Radio.Group = RadioGroup;
|
||||
|
||||
if (__DEV__) {
|
||||
Radio.displayName = "NextUI.Radio";
|
||||
}
|
||||
|
||||
Radio.toString = () => ".nextui-radio";
|
||||
|
||||
export default Radio;
|
||||
89
packages/components/radio/src/use-radio-group.ts
Normal file
89
packages/components/radio/src/use-radio-group.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import type {AriaRadioGroupProps} from "@react-types/radio";
|
||||
import type {Orientation} from "@react-types/shared";
|
||||
import type {NormalSizes, SimpleColors} from "@nextui-org/shared-utils";
|
||||
|
||||
import {useMemo, HTMLAttributes} from "react";
|
||||
import {RadioGroupState, useRadioGroupState} from "@react-stately/radio";
|
||||
import {useRadioGroup as useReactAriaRadioGroup} from "@react-aria/radio";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
|
||||
interface Props extends HTMLNextUIProps<"div"> {
|
||||
/**
|
||||
* The color of the radios.
|
||||
* @default "default"
|
||||
*/
|
||||
color?: SimpleColors;
|
||||
/**
|
||||
* The color of the radios's label.
|
||||
* @default "default"
|
||||
*/
|
||||
labelColor?: SimpleColors;
|
||||
/**
|
||||
* The size of the radios.
|
||||
* @default "md"
|
||||
*/
|
||||
size?: NormalSizes;
|
||||
/**
|
||||
* The axis the radio group items should align with.
|
||||
* @default "vertical"
|
||||
*/
|
||||
orientation?: Orientation;
|
||||
}
|
||||
|
||||
export type UseRadioGroupProps = AriaRadioGroupProps & Props;
|
||||
|
||||
interface IRadioGroupAria {
|
||||
/** Props for the radio group wrapper element. */
|
||||
radioGroupProps: Omit<HTMLAttributes<HTMLElement>, "css">;
|
||||
/** Props for the radio group's visible label (if any). */
|
||||
labelProps: Omit<HTMLAttributes<HTMLElement>, "css">;
|
||||
}
|
||||
|
||||
export type ContextType = {
|
||||
groupState: RadioGroupState;
|
||||
isRequired?: UseRadioGroupProps["isRequired"];
|
||||
color?: UseRadioGroupProps["color"];
|
||||
labelColor?: UseRadioGroupProps["labelColor"];
|
||||
size?: UseRadioGroupProps["size"];
|
||||
validationState?: UseRadioGroupProps["validationState"];
|
||||
};
|
||||
|
||||
export function useRadioGroup(props: UseRadioGroupProps) {
|
||||
const {
|
||||
size = "md",
|
||||
color = "default",
|
||||
labelColor = "default",
|
||||
orientation = "vertical",
|
||||
isRequired,
|
||||
validationState,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const otherPropsWithOrientation = useMemo<AriaRadioGroupProps>(() => {
|
||||
return {
|
||||
...otherProps,
|
||||
isRequired,
|
||||
orientation,
|
||||
};
|
||||
}, [otherProps]);
|
||||
|
||||
const groupState = useRadioGroupState(otherPropsWithOrientation);
|
||||
|
||||
const {labelProps, radioGroupProps: groupProps}: IRadioGroupAria = useReactAriaRadioGroup(
|
||||
otherPropsWithOrientation,
|
||||
groupState,
|
||||
);
|
||||
|
||||
const context: ContextType = {
|
||||
size,
|
||||
color,
|
||||
labelColor,
|
||||
groupState,
|
||||
isRequired,
|
||||
validationState,
|
||||
};
|
||||
|
||||
return {size, orientation, labelProps, groupProps, context, ...otherProps};
|
||||
}
|
||||
|
||||
export type UseRadioGroupReturn = ReturnType<typeof useRadioGroup>;
|
||||
126
packages/components/radio/src/use-radio.ts
Normal file
126
packages/components/radio/src/use-radio.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import type {AriaRadioProps} from "@react-types/radio";
|
||||
import type {IFocusRingAria} from "@nextui-org/dom-utils";
|
||||
|
||||
import {useMemo, useRef} from "react";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
import {useHover} from "@react-aria/interactions";
|
||||
import {useRadio as useReactAriaRadio} from "@react-aria/radio";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {NormalSizes, SimpleColors, __DEV__, warn} from "@nextui-org/shared-utils";
|
||||
|
||||
import {useRadioGroupContext} from "./radio-group-context";
|
||||
|
||||
interface Props extends HTMLNextUIProps<"label"> {
|
||||
/**
|
||||
* The content to display as the label.
|
||||
*/
|
||||
label?: string;
|
||||
/**
|
||||
* The color of the radio.
|
||||
* @default "default"
|
||||
*/
|
||||
color?: SimpleColors;
|
||||
/**
|
||||
* The color of the label.
|
||||
* @default "default"
|
||||
*/
|
||||
labelColor?: SimpleColors;
|
||||
/**
|
||||
* The size of the radio.
|
||||
* @default "md"
|
||||
*/
|
||||
size?: NormalSizes;
|
||||
/**
|
||||
* The radio description text.
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* Whether the radio is squared.
|
||||
* @default false
|
||||
*/
|
||||
isSquared?: boolean;
|
||||
/**
|
||||
* Whether the radio has animations.
|
||||
* @default false
|
||||
*/
|
||||
disableAnimation?: boolean;
|
||||
}
|
||||
|
||||
export type UseRadioProps = Props & AriaRadioProps;
|
||||
|
||||
export function useRadio(props: UseRadioProps) {
|
||||
const groupContext = useRadioGroupContext();
|
||||
|
||||
const {
|
||||
size = groupContext?.size ?? "md",
|
||||
color = groupContext?.color ?? "default",
|
||||
labelColor = groupContext?.labelColor ?? "default",
|
||||
autoFocus = false,
|
||||
isSquared = false,
|
||||
isDisabled: isDisabledProp = false,
|
||||
disableAnimation = false,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
if (groupContext && __DEV__) {
|
||||
if ("checked" in otherProps) {
|
||||
warn('Remove props "checked" if in the Radio.Group.', "Radio");
|
||||
}
|
||||
if (otherProps.value === undefined) {
|
||||
warn('Props "value" must be defined if in the Radio.Group.', "Radio");
|
||||
}
|
||||
}
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const {inputProps} = useReactAriaRadio(
|
||||
{
|
||||
...otherProps,
|
||||
...groupContext,
|
||||
isDisabled: isDisabledProp,
|
||||
},
|
||||
groupContext.groupState,
|
||||
inputRef,
|
||||
);
|
||||
|
||||
const isDisabled = useMemo(() => inputProps.disabled ?? false, [inputProps.disabled]);
|
||||
const isRequired = useMemo(() => groupContext.isRequired ?? false, [groupContext.isRequired]);
|
||||
const isInvalid = useMemo(
|
||||
() => groupContext.validationState === "invalid",
|
||||
[groupContext.validationState],
|
||||
);
|
||||
|
||||
const {hoverProps, isHovered} = useHover({isDisabled});
|
||||
|
||||
const {focusProps, isFocusVisible}: IFocusRingAria<UseRadioProps> = useFocusRing({
|
||||
autoFocus,
|
||||
});
|
||||
|
||||
const state = useMemo(() => {
|
||||
if (isHovered) return "hovered";
|
||||
if (isDisabled) return "disabled";
|
||||
|
||||
return inputProps.checked ? "checked" : "uncheked";
|
||||
}, [isDisabled, inputProps.checked, isHovered]);
|
||||
|
||||
return {
|
||||
state,
|
||||
size,
|
||||
color,
|
||||
labelColor,
|
||||
inputRef,
|
||||
isDisabled,
|
||||
isRequired,
|
||||
isInvalid,
|
||||
isHovered,
|
||||
isSquared,
|
||||
isFocusVisible,
|
||||
disableAnimation,
|
||||
hoverProps,
|
||||
focusProps,
|
||||
inputProps,
|
||||
...otherProps,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseRadioReturn = ReturnType<typeof useRadio>;
|
||||
247
packages/components/radio/stories/radio.stories.tsx
Normal file
247
packages/components/radio/stories/radio.stories.tsx
Normal file
@ -0,0 +1,247 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {Button} from "@nextui-org/button";
|
||||
import {Spacer} from "@nextui-org/spacer";
|
||||
|
||||
import {Radio} from "../src";
|
||||
|
||||
export default {
|
||||
title: "Inputs/Radio",
|
||||
component: Radio,
|
||||
onChange: {action: "changed"},
|
||||
} as Meta;
|
||||
|
||||
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>
|
||||
);
|
||||
|
||||
const handleSubmit = (e: any) => {
|
||||
e.preventDefault();
|
||||
alert("Submitted!");
|
||||
};
|
||||
|
||||
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 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>
|
||||
);
|
||||
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
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>
|
||||
);
|
||||
};
|
||||
9
packages/components/radio/tsconfig.json
Normal file
9
packages/components/radio/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"]
|
||||
}
|
||||
},
|
||||
"include": ["src", "index.ts"]
|
||||
}
|
||||
13
packages/components/radio/tsup.config.ts
Normal file
13
packages/components/radio/tsup.config.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import {defineConfig} from "tsup";
|
||||
import {findUpSync} from "find-up";
|
||||
|
||||
export default defineConfig({
|
||||
clean: true,
|
||||
minify: false,
|
||||
treeshake: true,
|
||||
format: ["cjs", "esm"],
|
||||
outExtension(ctx) {
|
||||
return {js: `.${ctx.format}.js`};
|
||||
},
|
||||
inject: process.env.JSX ? [findUpSync("react-shim.js")!] : undefined,
|
||||
});
|
||||
@ -2,8 +2,7 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"],
|
||||
"@react-types/link": ["../../../node_modules/@react-types/link"],
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"]
|
||||
}
|
||||
},
|
||||
"include": ["src", "index.ts"]
|
||||
|
||||
@ -54,12 +54,13 @@
|
||||
"@nextui-org/image": "workspace:*",
|
||||
"@nextui-org/link": "workspace:*",
|
||||
"@nextui-org/loading": "workspace:*",
|
||||
"@nextui-org/pagination": "workspace:*",
|
||||
"@nextui-org/radio": "workspace:*",
|
||||
"@nextui-org/row": "workspace:*",
|
||||
"@nextui-org/snippet": "workspace:*",
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"@nextui-org/text": "workspace:*",
|
||||
"@nextui-org/user": "workspace:*",
|
||||
"@nextui-org/pagination": "workspace:*"
|
||||
"@nextui-org/user": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
|
||||
@ -10,3 +10,4 @@ export * from "@nextui-org/text";
|
||||
export * from "@nextui-org/link";
|
||||
export * from "@nextui-org/code";
|
||||
export * from "@nextui-org/pagination";
|
||||
export * from "@nextui-org/radio";
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"],
|
||||
"@react-types/link": ["../../../node_modules/@react-types/link"]
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"]
|
||||
}
|
||||
},
|
||||
"include": ["src", "index.ts"]
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/shared": "^3.15.0",
|
||||
"@react-aria/interactions": "^3.12.0",
|
||||
"@react-aria/focus": "^3.9.0"
|
||||
},
|
||||
|
||||
15
packages/utilities/shared-utils/src/console.ts
Normal file
15
packages/utilities/shared-utils/src/console.ts
Normal file
@ -0,0 +1,15 @@
|
||||
const warningStack: {[key: string]: boolean} = {};
|
||||
|
||||
export function warn(message: string, component?: string, ...args: any[]) {
|
||||
const tag = component ? ` [${component}]` : " ";
|
||||
const log = `[Next UI]${tag}: ${message}`;
|
||||
|
||||
if (typeof console === "undefined") return;
|
||||
if (warningStack[log]) return;
|
||||
warningStack[log] = true;
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
// eslint-disable-next-line no-console
|
||||
return console.warn(log, args);
|
||||
}
|
||||
}
|
||||
@ -12,3 +12,4 @@ export * from "./css-transition";
|
||||
export * from "./functions";
|
||||
export * from "./context";
|
||||
export * from "./numbers";
|
||||
export * from "./console";
|
||||
|
||||
86
pnpm-lock.yaml
generated
86
pnpm-lock.yaml
generated
@ -21,7 +21,7 @@ importers:
|
||||
'@docusaurus/utils': 2.0.0-beta.3
|
||||
'@react-bootstrap/babel-preset': ^2.1.0
|
||||
'@react-types/link': ^3.3.3
|
||||
'@react-types/shared': ^3.14.1
|
||||
'@react-types/shared': ^3.15.0
|
||||
'@storybook/addon-a11y': ^6.5.3
|
||||
'@storybook/addon-actions': ^6.5.3
|
||||
'@storybook/addon-essentials': ^6.5.3
|
||||
@ -372,7 +372,7 @@ importers:
|
||||
'@react-aria/interactions': ^3.12.0
|
||||
'@react-aria/utils': ^3.14.0
|
||||
'@react-types/button': ^3.6.2
|
||||
'@react-types/shared': ^3.14.1
|
||||
'@react-types/shared': ^3.15.0
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
@ -413,7 +413,7 @@ importers:
|
||||
'@react-aria/focus': ^3.9.0
|
||||
'@react-aria/interactions': ^3.12.0
|
||||
'@react-aria/utils': ^3.14.0
|
||||
'@react-types/shared': ^3.14.1
|
||||
'@react-types/shared': ^3.15.0
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
@ -452,7 +452,7 @@ importers:
|
||||
'@react-stately/checkbox': ^3.3.0
|
||||
'@react-stately/toggle': ^3.4.2
|
||||
'@react-types/checkbox': ^3.4.0
|
||||
'@react-types/shared': ^3.14.1
|
||||
'@react-types/shared': ^3.15.0
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
@ -660,6 +660,43 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/radio:
|
||||
specifiers:
|
||||
'@nextui-org/button': workspace:*
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/shared-css': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/spacer': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
'@react-aria/focus': ^3.9.0
|
||||
'@react-aria/interactions': ^3.12.0
|
||||
'@react-aria/radio': ^3.4.0
|
||||
'@react-aria/utils': ^3.14.0
|
||||
'@react-aria/visually-hidden': ^3.5.0
|
||||
'@react-stately/radio': ^3.6.0
|
||||
'@react-types/radio': ^3.3.0
|
||||
'@react-types/shared': ^3.15.0
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
'@nextui-org/shared-css': link:../../utilities/shared-css
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
'@react-aria/focus': 3.9.0_react@17.0.2
|
||||
'@react-aria/interactions': 3.12.0_react@17.0.2
|
||||
'@react-aria/radio': 3.4.0_react@17.0.2
|
||||
'@react-aria/utils': 3.14.0_react@17.0.2
|
||||
'@react-aria/visually-hidden': 3.5.0_react@17.0.2
|
||||
'@react-stately/radio': 3.6.0_react@17.0.2
|
||||
devDependencies:
|
||||
'@nextui-org/button': link:../button
|
||||
'@nextui-org/spacer': link:../spacer
|
||||
'@react-types/radio': 3.3.0_react@17.0.2
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/row:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
@ -766,6 +803,7 @@ importers:
|
||||
'@nextui-org/link': workspace:*
|
||||
'@nextui-org/loading': workspace:*
|
||||
'@nextui-org/pagination': workspace:*
|
||||
'@nextui-org/radio': workspace:*
|
||||
'@nextui-org/row': workspace:*
|
||||
'@nextui-org/snippet': workspace:*
|
||||
'@nextui-org/spacer': workspace:*
|
||||
@ -791,6 +829,7 @@ importers:
|
||||
'@nextui-org/link': link:../../components/link
|
||||
'@nextui-org/loading': link:../../components/loading
|
||||
'@nextui-org/pagination': link:../../components/pagination
|
||||
'@nextui-org/radio': link:../../components/radio
|
||||
'@nextui-org/row': link:../../components/row
|
||||
'@nextui-org/snippet': link:../../components/snippet
|
||||
'@nextui-org/spacer': link:../../components/spacer
|
||||
@ -879,7 +918,7 @@ importers:
|
||||
specifiers:
|
||||
'@react-aria/focus': ^3.9.0
|
||||
'@react-aria/interactions': ^3.12.0
|
||||
'@react-types/shared': ^3.14.1
|
||||
'@react-types/shared': ^3.15.0
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
@ -4893,6 +4932,23 @@ packages:
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-aria/radio/3.4.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-DUccHQxfI0PikXXQKarh/hLS/G+ZzfdQ00/sd57jzWsuRyukb+WywQhud29p5uO3wT33/MH9LZgSmb9dlvfabQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.19.0
|
||||
'@react-aria/focus': 3.9.0_react@17.0.2
|
||||
'@react-aria/i18n': 3.6.1_react@17.0.2
|
||||
'@react-aria/interactions': 3.12.0_react@17.0.2
|
||||
'@react-aria/label': 3.4.2_react@17.0.2
|
||||
'@react-aria/utils': 3.14.0_react@17.0.2
|
||||
'@react-stately/radio': 3.6.0_react@17.0.2
|
||||
'@react-types/radio': 3.3.0_react@17.0.2
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-aria/ssr/3.3.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-yNqUDuOVZIUGP81R87BJVi/ZUZp/nYOBXbPsRe7oltJOfErQZD+UezMpw4vM2KRz18cURffvmC8tJ6JTeyDtaQ==}
|
||||
peerDependencies:
|
||||
@ -5003,6 +5059,18 @@ packages:
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-stately/radio/3.6.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-hzNwIapDSnbk5mCim/AgHQTtHRgy2QiW95okfVnGflzO7nnws8WH/s2Va4f7UupWObPv8XTqHADUEng86mVBJA==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.19.0
|
||||
'@react-stately/utils': 3.5.1_react@17.0.2
|
||||
'@react-types/radio': 3.3.0_react@17.0.2
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-stately/toggle/3.4.2_react@17.0.2:
|
||||
resolution: {integrity: sha512-+pO13Ap/tj4optu6VjQrEAaAoZvJAEwarMUaZvrkc0kdvMTNPdiT/2vhN32yvsSW0ssuFqToa3jMrTylCbpo8w==}
|
||||
peerDependencies:
|
||||
@ -5066,6 +5134,14 @@ packages:
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-types/radio/3.3.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-aF4OpGjd9/xuRnDSDJnmwzLvvOENUWSHQc//wp8rViCWf1uinY4wHI/J3uEhodhsUPAKmrqvUagphRoyXWZA8A==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||
dependencies:
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
react: 17.0.2
|
||||
|
||||
/@react-types/shared/3.15.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-hwuE4BmgswqP+HRDSLMj7DcnYOCCK+ZRuKnc9AVhXS4LBrwRSkdUkNvXhgvqF5tav7IqTpG9pBYMR9wedehuhA==}
|
||||
peerDependencies:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user