Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

Commit c960f15

Browse files
authoredJan 17, 2025··
fix: refactored Switch and Checkbox from shadcn (#116)
1 parent 31bcaed commit c960f15

File tree

10 files changed

+333
-58
lines changed

10 files changed

+333
-58
lines changed
 

‎src/components/Form/FormControllers/ApplicationQuestionsFormController/ApplicationQuestionsFormController.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { PlusIcon } from "@heroicons/react/outline";
88
import { X } from "lucide-react";
99

1010
import { Button } from "@/primitives/Button";
11-
import { Checkbox } from "@/ui-shadcn/checkbox";
11+
import { Checkbox } from "@/primitives/Checkbox";
12+
import { Switch } from "@/primitives/Switch";
1213
import { Input } from "@/ui-shadcn/input";
1314
import { Label } from "@/ui-shadcn/label";
1415
import { Select, SelectTrigger, SelectContent, SelectItem } from "@/ui-shadcn/select";
15-
import { Switch } from "@/ui-shadcn/switch";
1616

1717
import { inputTypes } from "./utils";
1818

‎src/components/Form/FormControllers/RoundDatesFormController/RoundDatesFormController.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useFormContext, Controller } from "react-hook-form";
55

66
import moment from "moment-timezone";
77

8-
import { Checkbox } from "@/ui-shadcn/checkbox";
8+
import { Checkbox } from "@/primitives/Checkbox";
99
import { Label } from "@/ui-shadcn/label";
1010
import { Select, SelectTrigger, SelectContent, SelectItem } from "@/ui-shadcn/select";
1111

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
3+
import { Checkbox } from "./Checkbox";
4+
5+
const meta: Meta<typeof Checkbox> = {
6+
title: "Primitives/Checkbox",
7+
component: Checkbox,
8+
tags: ["autodocs"],
9+
};
10+
11+
export default meta;
12+
type Story = StoryObj<typeof Checkbox>;
13+
14+
// Small Checkboxes Story
15+
export const SmallCheckboxes: Story = {
16+
render: () => (
17+
<div className="flex items-center gap-4">
18+
<Checkbox size="sm" color="moss" defaultChecked />
19+
<Checkbox size="sm" color="black" defaultChecked />
20+
<Checkbox size="sm" color="white" defaultChecked />
21+
<Checkbox size="sm" color="purple" defaultChecked />
22+
</div>
23+
),
24+
};
25+
26+
// Medium Checkboxes Story
27+
export const MediumCheckboxes: Story = {
28+
render: () => (
29+
<div className="flex items-center gap-4">
30+
<Checkbox size="md" color="moss" defaultChecked />
31+
<Checkbox size="md" color="black" defaultChecked />
32+
<Checkbox size="md" color="white" defaultChecked />
33+
<Checkbox size="md" color="purple" defaultChecked />
34+
</div>
35+
),
36+
};
37+
38+
// Large Checkboxes Story
39+
export const LargeCheckboxes: Story = {
40+
render: () => (
41+
<div className="flex items-center gap-4">
42+
<Checkbox size="lg" color="moss" defaultChecked />
43+
<Checkbox size="lg" color="black" defaultChecked />
44+
<Checkbox size="lg" color="white" defaultChecked />
45+
<Checkbox size="lg" color="purple" defaultChecked />
46+
</div>
47+
),
48+
};
49+
50+
// Interactive Checkbox Story with Controls
51+
export const Interactive: Story = {
52+
args: {
53+
size: "md",
54+
color: "moss",
55+
defaultChecked: true,
56+
},
57+
argTypes: {
58+
size: {
59+
control: "select",
60+
options: ["sm", "md", "lg"],
61+
},
62+
color: {
63+
control: "select",
64+
options: ["moss", "black", "white", "purple"],
65+
},
66+
defaultChecked: {
67+
control: "boolean",
68+
},
69+
},
70+
};
71+
72+
// States Story
73+
export const States: Story = {
74+
render: () => (
75+
<div className="flex flex-col gap-4">
76+
<div className="flex items-center gap-4">
77+
<Checkbox color="moss" />
78+
<span className="text-sm">Unchecked</span>
79+
</div>
80+
<div className="flex items-center gap-4">
81+
<Checkbox color="moss" defaultChecked />
82+
<span className="text-sm">Checked</span>
83+
</div>
84+
<div className="flex items-center gap-4">
85+
<Checkbox color="moss" disabled />
86+
<span className="text-sm">Disabled Unchecked</span>
87+
</div>
88+
<div className="flex items-center gap-4">
89+
<Checkbox color="moss" disabled defaultChecked />
90+
<span className="text-sm">Disabled Checked</span>
91+
</div>
92+
</div>
93+
),
94+
};

‎src/primitives/Checkbox/Checkbox.tsx

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"use client";
2+
3+
import * as React from "react";
4+
5+
import { CheckIcon } from "@heroicons/react/solid";
6+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
7+
import { tv, VariantProps } from "tailwind-variants";
8+
9+
import { cn } from "@/lib/utils";
10+
11+
const checkboxVariants = tv({
12+
slots: {
13+
base: "peer size-4 rounded-sm border border-moss-300 text-center ring-offset-white hover:border-moss-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-moss-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-moss-500 data-[state=checked]:text-grey-50",
14+
},
15+
variants: {
16+
size: {
17+
sm: {
18+
base: "size-4",
19+
},
20+
md: {
21+
base: "size-5",
22+
},
23+
lg: {
24+
base: "size-6",
25+
},
26+
},
27+
color: {
28+
moss: {
29+
base: "border-moss-700 hover:border-moss-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-moss-900 focus-visible:ring-offset-2 data-[state=checked]:bg-moss-700 data-[state=unchecked]:bg-transparent data-[state=checked]:text-white data-[state=unchecked]:text-white",
30+
},
31+
black: {
32+
base: "border-grey-300 hover:border-grey-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-grey-500 focus-visible:ring-offset-2 data-[state=checked]:bg-black data-[state=unchecked]:bg-transparent data-[state=checked]:text-grey-50 data-[state=unchecked]:text-grey-50",
33+
},
34+
white: {
35+
base: "border-black hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 data-[state=checked]:bg-white data-[state=unchecked]:bg-transparent data-[state=checked]:text-black data-[state=unchecked]:text-black dark:border-grey-50 dark:hover:border-grey-200 dark:focus-visible:ring-grey-200 dark:data-[state=checked]:bg-grey-50 dark:data-[state=checked]:text-black dark:data-[state=unchecked]:text-grey-50",
36+
},
37+
purple: {
38+
base: "border-purple-700 hover:border-purple-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-purple-900 focus-visible:ring-offset-2 data-[state=checked]:bg-purple-700 data-[state=unchecked]:bg-transparent data-[state=checked]:text-grey-50 data-[state=unchecked]:text-white",
39+
},
40+
},
41+
},
42+
defaultVariants: {
43+
size: "sm",
44+
color: "moss",
45+
},
46+
});
47+
48+
export type CheckboxVariants = VariantProps<typeof checkboxVariants>;
49+
50+
const Checkbox = React.forwardRef<
51+
React.ElementRef<typeof CheckboxPrimitive.Root>,
52+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> & CheckboxVariants
53+
>(({ className, ...props }, ref) => {
54+
const { size, color, ...rest } = props;
55+
const { base } = checkboxVariants({ size, color });
56+
57+
return (
58+
<CheckboxPrimitive.Root ref={ref} className={cn(base(), className)} {...rest}>
59+
<CheckboxPrimitive.Indicator>
60+
<CheckIcon />
61+
</CheckboxPrimitive.Indicator>
62+
</CheckboxPrimitive.Root>
63+
);
64+
});
65+
66+
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
67+
68+
export { Checkbox };

‎src/primitives/Checkbox/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Checkbox } from "./Checkbox";
+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
3+
import { Switch } from "./Switch";
4+
5+
const meta: Meta<typeof Switch> = {
6+
title: "Primitives/Switch",
7+
component: Switch,
8+
tags: ["autodocs"],
9+
};
10+
11+
export default meta;
12+
type Story = StoryObj<typeof Switch>;
13+
14+
// Color Variants Story
15+
export const ColorVariants: Story = {
16+
render: () => (
17+
<div className="flex flex-col gap-4">
18+
<div className="flex items-center gap-4">
19+
<Switch color="moss" defaultChecked />
20+
<span className="text-sm">Moss</span>
21+
</div>
22+
<div className="flex items-center gap-4">
23+
<Switch color="black" defaultChecked />
24+
<span className="text-sm">Black</span>
25+
</div>
26+
<div className="flex items-center gap-4">
27+
<Switch color="purple" defaultChecked />
28+
<span className="text-sm">Purple</span>
29+
</div>
30+
<div className="flex items-center gap-4">
31+
<Switch color="white" defaultChecked />
32+
<span className="text-sm">White</span>
33+
</div>
34+
</div>
35+
),
36+
};
37+
38+
// States Story
39+
export const States: Story = {
40+
render: () => (
41+
<div className="flex flex-col gap-4">
42+
<div className="flex items-center gap-4">
43+
<Switch color="moss" />
44+
<span className="text-sm">Unchecked</span>
45+
</div>
46+
<div className="flex items-center gap-4">
47+
<Switch color="moss" defaultChecked />
48+
<span className="text-sm">Checked</span>
49+
</div>
50+
<div className="flex items-center gap-4">
51+
<Switch color="moss" disabled />
52+
<span className="text-sm">Disabled Unchecked</span>
53+
</div>
54+
<div className="flex items-center gap-4">
55+
<Switch color="moss" disabled defaultChecked />
56+
<span className="text-sm">Disabled Checked</span>
57+
</div>
58+
</div>
59+
),
60+
};
61+
62+
// Interactive Story with Controls
63+
export const Interactive: Story = {
64+
args: {
65+
color: "moss",
66+
defaultChecked: true,
67+
disabled: false,
68+
},
69+
argTypes: {
70+
color: {
71+
control: "select",
72+
options: ["moss", "black", "purple", "white"],
73+
},
74+
defaultChecked: {
75+
control: "boolean",
76+
},
77+
disabled: {
78+
control: "boolean",
79+
},
80+
},
81+
};
82+
83+
// Group Story
84+
export const Group: Story = {
85+
render: () => (
86+
<div className="space-y-8">
87+
<div className="flex items-center justify-between">
88+
<label htmlFor="airplane-mode" className="text-sm font-medium">
89+
Airplane Mode
90+
</label>
91+
<Switch id="airplane-mode" color="moss" />
92+
</div>
93+
<div className="flex items-center justify-between">
94+
<label htmlFor="wifi" className="text-sm font-medium">
95+
Wi-Fi
96+
</label>
97+
<Switch id="wifi" color="purple" defaultChecked />
98+
</div>
99+
<div className="flex items-center justify-between">
100+
<label htmlFor="notifications" className="text-sm font-medium">
101+
Notifications
102+
</label>
103+
<Switch id="notifications" color="black" defaultChecked />
104+
</div>
105+
</div>
106+
),
107+
};

‎src/primitives/Switch/Switch.tsx

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"use client";
2+
3+
import * as React from "react";
4+
5+
import * as SwitchPrimitives from "@radix-ui/react-switch";
6+
import { tv, VariantProps } from "tailwind-variants";
7+
8+
import { cn } from "@/lib/utils";
9+
10+
const switchVariants = tv({
11+
slots: {
12+
base: "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-moss-700 data-[state=unchecked]:bg-grey-100",
13+
thumb:
14+
"pointer-events-none block h-5 w-5 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
15+
},
16+
variants: {
17+
color: {
18+
moss: {
19+
base: "data-[state=checked]:bg-moss-700 data-[state=unchecked]:bg-grey-100",
20+
thumb: "bg-white",
21+
},
22+
black: {
23+
base: "data-[state=checked]:bg-black data-[state=unchecked]:bg-grey-100",
24+
thumb: "bg-white",
25+
},
26+
purple: {
27+
base: "data-[state=checked]:bg-purple-700 data-[state=unchecked]:bg-grey-100",
28+
thumb: "bg-white",
29+
},
30+
white: {
31+
base: "data-[state=checked]:bg-white data-[state=unchecked]:bg-grey-100",
32+
thumb: "bg-black",
33+
},
34+
},
35+
},
36+
defaultVariants: {
37+
color: "moss",
38+
},
39+
});
40+
41+
type SwitchVariants = VariantProps<typeof switchVariants>;
42+
43+
const Switch = React.forwardRef<
44+
React.ElementRef<typeof SwitchPrimitives.Root>,
45+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> & SwitchVariants
46+
>(({ className, ...props }, ref) => {
47+
const { color, ...rest } = props;
48+
const { base, thumb } = switchVariants({ color });
49+
50+
return (
51+
<SwitchPrimitives.Root className={cn(base(), className)} {...rest} ref={ref}>
52+
<SwitchPrimitives.Thumb className={thumb()} />
53+
</SwitchPrimitives.Root>
54+
);
55+
});
56+
57+
Switch.displayName = SwitchPrimitives.Root.displayName;
58+
59+
export { Switch };

‎src/primitives/Switch/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Switch } from "./Switch";

‎src/ui-shadcn/checkbox.tsx

-27
This file was deleted.

‎src/ui-shadcn/switch.tsx

-28
This file was deleted.

0 commit comments

Comments
 (0)
This repository has been archived.