diff --git a/package.json b/package.json
index 1db03b9..e05203d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@continha/ui",
- "version": "1.3.1",
+ "version": "1.4.0",
"private": false,
"repository": {
"url": "https://github.com/bearkfear/ui"
@@ -14,7 +14,9 @@
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
- "files": ["dist"],
+ "files": [
+ "dist"
+ ],
"peerDependencies": {
"@continha/formbuilder": "^1.0.2",
"@radix-ui/colors": "^3.0.0",
@@ -31,7 +33,6 @@
"tailwind-merge": "^2.4.0"
},
"devDependencies": {
- "@swc/core": "^1.3.35",
"@biomejs/biome": "^1.8.3",
"@storybook/addon-essentials": "^8.2.4",
"@storybook/addon-interactions": "^8.2.4",
@@ -42,6 +43,7 @@
"@storybook/nextjs": "^8.2.4",
"@storybook/react": "^8.2.4",
"@storybook/test": "^8.2.4",
+ "@swc/core": "^1.3.35",
"@types/lodash.get": "^4.4.9",
"@types/lodash.isequal": "^4.5.8",
"@types/node": "^20",
@@ -60,6 +62,7 @@
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
+ "@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c45b423..537ae58 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -29,6 +29,9 @@ importers:
'@radix-ui/react-popover':
specifier: ^1.1.1
version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-radio-group':
+ specifier: ^1.2.0
+ version: 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-separator':
specifier: ^1.1.0
version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -1483,6 +1486,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-collection@1.1.0':
+ resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-compose-refs@1.0.1':
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
peerDependencies:
@@ -1545,6 +1561,15 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-direction@1.1.0':
+ resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-dismissable-layer@1.0.5':
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
peerDependencies:
@@ -1750,6 +1775,32 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-radio-group@1.2.0':
+ resolution: {integrity: sha512-yv+oiLaicYMBpqgfpSPw6q+RyXlLdIpQWDHZbUKURxe+nEh53hFXPPlfhfQQtYkS5MMK/5IWIa76SksleQZSzw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-roving-focus@1.1.0':
+ resolution: {integrity: sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-separator@1.1.0':
resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==}
peerDependencies:
@@ -6655,6 +6706,18 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
+ '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.3
+ '@types/react-dom': 18.3.0
+
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.3)(react@18.3.1)':
dependencies:
'@babel/runtime': 7.25.0
@@ -6726,6 +6789,12 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
+ '@radix-ui/react-direction@1.1.0(@types/react@18.3.3)(react@18.3.1)':
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.3
+
'@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@babel/runtime': 7.25.0
@@ -6914,6 +6983,41 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
+ '@radix-ui/react-radio-group@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.3
+ '@types/react-dom': 18.3.0
+
+ '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.3
+ '@types/react-dom': 18.3.0
+
'@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
diff --git a/src/components/ui/form/form-builder.tsx b/src/components/ui/form/form-builder.tsx
index 76b7bfb..fb387dc 100644
--- a/src/components/ui/form/form-builder.tsx
+++ b/src/components/ui/form/form-builder.tsx
@@ -11,6 +11,7 @@ import { Label } from "./label";
import { MultiSelector, SingleSelector } from "./selector";
import { Textarea } from "./textarea";
import { Checkbox } from "./checkbox";
+import * as Radio from "./radio";
function FormControl(props: FormRenderProps) {
const disabled = props.field.disabled || props.fieldConfig.disabled;
@@ -99,6 +100,34 @@ function FormControl(props: FormRenderProps) {
);
}
+ if (props.fieldConfig.type === "radio") {
+ const options = props.fieldConfig.options || [];
+
+ return (
+
+ props.field.onChange(
+ options.find((option) => `${option.value}` === newValue)?.value,
+ )
+ }
+ >
+ {props.fieldConfig.options?.map((option) => {
+ const id = `radio-${props.fieldConfig.name}-option${option.value}`;
+ return (
+
+
+
+
+ );
+ })}
+
+ );
+ }
+
return null;
}
diff --git a/src/components/ui/form/label.tsx b/src/components/ui/form/label.tsx
index 52d7a47..1ffcad7 100644
--- a/src/components/ui/form/label.tsx
+++ b/src/components/ui/form/label.tsx
@@ -8,7 +8,7 @@ import { LuAsterisk } from "react-icons/lu";
import { cn } from "~/lib/utils";
const labelVariants = cva(
- "text-xs text-black dark:text-white font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+ "text-xs text-black dark:text-white leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 font-bold",
);
const Label = React.forwardRef<
diff --git a/src/components/ui/form/radio.tsx b/src/components/ui/form/radio.tsx
new file mode 100644
index 0000000..832b7f6
--- /dev/null
+++ b/src/components/ui/form/radio.tsx
@@ -0,0 +1,46 @@
+"use client";
+
+import * as React from "react";
+import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
+import { Circle } from "lucide-react";
+
+import { cn } from "~/lib/utils";
+
+const Group = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => {
+ return (
+
+ );
+});
+Group.displayName = RadioGroupPrimitive.Root.displayName;
+
+const Item = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => {
+ return (
+
+
+
+
+
+ );
+});
+Item.displayName = RadioGroupPrimitive.Item.displayName;
+
+const Root = RadioGroupPrimitive.Root;
+
+export { Group, Item, Root };
diff --git a/src/stories/form/form-item.stories.tsx b/src/stories/form/form-item.stories.tsx
index a186f2f..bef973d 100644
--- a/src/stories/form/form-item.stories.tsx
+++ b/src/stories/form/form-item.stories.tsx
@@ -211,3 +211,33 @@ export const Checkbox = () => {
);
};
+
+export const Radio = () => {
+ const form = useForm({
+ defaultValues: {
+ gender: "",
+ },
+ });
+
+ return (
+
+
+
+ );
+};