generated from codersforcauses/django-nextjs-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Issue 64 add checkbox group component #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
EdenWuyt
wants to merge
9
commits into
main
Choose a base branch
from
issue-64-Add_Checkbox_Group_component
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
99a30e0
Add checkbox component. No test and documentation yet.
EdenWuyt 448cc22
Add test page for checkbox component. Update styling.
EdenWuyt fb07789
Add documentation.
EdenWuyt 4fb5ff5
Update checkbox group styling from flex to grid.
EdenWuyt 85de83a
Fix Copilot suggestion 1: update texts in test page & add use client …
EdenWuyt 4014782
Fix Copilot suggestion 2: update documentation format.
EdenWuyt 6ed6033
Fix Copilot suggestion 3: update handleCheckedChange in CheckboxItem …
EdenWuyt 741cb2b
Fix Copilot suggestion 4: change wrapper from div to label in Checkbo…
EdenWuyt 71ab22b
Refactor checkbox and checkbox group components to align with shadcn …
EdenWuyt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| "use client"; | ||
| import { useState } from "react"; | ||
|
|
||
| import { CheckboxGroup, CheckboxItem } from "@/components/checkbox-group"; | ||
| import { Button } from "@/components/ui/button"; | ||
| import { Checkbox } from "@/components/ui/checkbox"; | ||
|
|
||
| const DATES = [ | ||
| "Monday", | ||
| "Tuesday", | ||
| "Wednesday", | ||
| "Thursday", | ||
| "Friday", | ||
| "Saturday", | ||
| "Sunday", | ||
| ]; | ||
|
|
||
| export default function CheckboxTestPage() { | ||
| const [acceptTerms, setAcceptTerms] = useState<boolean>(false); | ||
| const [dates, setDates] = useState<string[]>([]); | ||
|
|
||
| const handleSubmit = (e: React.FormEvent) => { | ||
| e.preventDefault(); | ||
| alert( | ||
| `Submitted data:\nacceptTerms: ${acceptTerms.toString()}\ndates: ${JSON.stringify(dates)}`, | ||
| ); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="min-h-screen p-8"> | ||
| <div className="mx-auto my-5 flex w-full max-w-lg flex-col items-center justify-center"> | ||
| <form onSubmit={handleSubmit} className="w-full rounded-md border p-4"> | ||
| {/* a single checkbox */} | ||
| <p className="title mb-3">A single checkbox</p> | ||
| <Checkbox | ||
| checked={acceptTerms} | ||
| onCheckedChange={(checked) => setAcceptTerms(checked === true)} // Radix Output can be true | false | "indeterminate" | ||
| > | ||
| <p> Accept terms and conditions. </p> | ||
| </Checkbox> | ||
| {/* a checkbox group */} | ||
| <p className="title mb-3 mt-5">A checkbox group</p> | ||
| <CheckboxGroup | ||
| value={dates} | ||
| onValueChange={setDates} | ||
| className="grid-cols-2" | ||
| > | ||
| {DATES.map((date) => ( | ||
| <CheckboxItem key={date} value={date} id={date}> | ||
| <p> {date} </p> | ||
| </CheckboxItem> | ||
| ))} | ||
| </CheckboxGroup> | ||
| <Button type="submit" className="mx-auto mt-4"> | ||
| Submit | ||
| </Button> | ||
| </form> | ||
| <p className="mt-4 text-center"> | ||
| Current acceptTerms value: {acceptTerms.toString()} | ||
| </p> | ||
| <p className="mt-4 text-center"> | ||
| Current dates message: {JSON.stringify(dates, null, 1)} | ||
| </p> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| /** | ||
| * Usage: | ||
| * | ||
| * A group of checkbox: use `[value, setValue] = useState<string[]>(initialValue)` to get the selected value | ||
| * ```tsx | ||
| * <CheckboxGroup value={value} onValueChange={setValue}> | ||
| * <CheckboxItem value={value1}>{children}</CheckboxItem> | ||
| * <CheckboxItem value={value2}>{children}</CheckboxItem> | ||
| * </CheckboxGroup> | ||
| * ``` | ||
| */ | ||
|
|
||
| "use client"; | ||
| import type { CheckedState } from "@radix-ui/react-checkbox"; | ||
| import React, { useCallback, useContext } from "react"; | ||
|
|
||
| import { Checkbox } from "@/components/ui/checkbox"; | ||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| type CheckboxGroupContextValue = { | ||
| value: string[]; | ||
| onChange: (itemValue: string, checked: boolean) => void; | ||
| }; | ||
|
|
||
| const CheckboxGroupContext = | ||
| React.createContext<CheckboxGroupContextValue | null>(null); | ||
|
|
||
| /** | ||
| * CheckboxGroup component for wrapping multiple CheckboxItem components and rendering a checkbox group. | ||
| */ | ||
| interface CheckboxGroupProps extends React.HTMLAttributes<HTMLDivElement> { | ||
| value: string[]; | ||
| onValueChange: (value: string[]) => void; | ||
| } | ||
|
|
||
| const CheckboxGroup = React.forwardRef<HTMLDivElement, CheckboxGroupProps>( | ||
| ({ className, value, onValueChange, children, ...props }, ref) => { | ||
| const onItemValueChange = useCallback( | ||
| (itemValue: string, checked: boolean) => { | ||
| if (checked) { | ||
| onValueChange([...value, itemValue]); | ||
| } else { | ||
| onValueChange(value.filter((v) => v !== itemValue)); | ||
| } | ||
| }, | ||
| [value, onValueChange], | ||
| ); | ||
|
|
||
| return ( | ||
| <CheckboxGroupContext.Provider | ||
| value={{ value, onChange: onItemValueChange }} | ||
| > | ||
| <div ref={ref} className={cn("grid gap-2", className)} {...props}> | ||
| {children} | ||
| </div> | ||
| </CheckboxGroupContext.Provider> | ||
| ); | ||
| }, | ||
| ); | ||
|
|
||
| CheckboxGroup.displayName = "CheckboxGroup"; | ||
|
|
||
| /** | ||
| * CheckboxItem component for rendering a single checkbox. Must used within CheckboxGroup. | ||
| */ | ||
| interface CheckboxItemProps | ||
| extends React.ComponentPropsWithoutRef<typeof Checkbox> { | ||
| value: string; | ||
| } | ||
|
|
||
| const CheckboxItem = React.forwardRef< | ||
| React.ElementRef<typeof Checkbox>, | ||
| CheckboxItemProps | ||
| >( | ||
| ( | ||
| { className, id: propsId, value, checked, onCheckedChange, ...props }, | ||
| ref, | ||
| ) => { | ||
| const context = useContext(CheckboxGroupContext); | ||
| const id = propsId || value; | ||
|
|
||
| if (!context) { | ||
| throw new Error("CheckboxItem must be used within a CheckboxGroup."); | ||
| } | ||
|
|
||
| const isChecked = context.value.includes(value); | ||
| const handleCheckedChange = (checked: CheckedState) => | ||
| context.onChange(value, checked === true); | ||
|
|
||
| return ( | ||
| <Checkbox | ||
| ref={ref} | ||
| id={id} | ||
| value={value} | ||
| className={className} | ||
| checked={isChecked} | ||
| onCheckedChange={handleCheckedChange} | ||
| {...props} | ||
| /> | ||
| ); | ||
| }, | ||
| ); | ||
|
|
||
| CheckboxItem.displayName = "CheckboxItem"; | ||
|
|
||
| export { CheckboxGroup, CheckboxItem }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /** | ||
| * Usage: | ||
| * | ||
| * A single checkbox: use `[checked, setChecked] = useState<boolean>(initialValue)` to get the checkbox status | ||
| * ```tsx | ||
| * <Checkbox | ||
| * checked={checked} | ||
| * onCheckedChange={(checked) => setChecked(checked === true)} // As Radix Output can be true | false | "indeterminate", simple pass setChecked will cause Typescript complaint | ||
| * // optional props can be passed as in standard html checkbox | ||
| * > | ||
| * {children} // add label here | ||
| * </Checkbox> | ||
| * ``` | ||
| * | ||
| * A group of checkbox: use CheckboxGroup | ||
| * | ||
| */ | ||
|
|
||
| "use client"; | ||
| import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; | ||
| import React from "react"; | ||
| import { FaCheck } from "react-icons/fa"; | ||
|
|
||
| import { Label } from "@/components/ui/label"; | ||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| /** | ||
| * Checkbox component for rendering a single checkbox. Used standalone. | ||
| */ | ||
| const Checkbox = React.forwardRef< | ||
| React.ElementRef<typeof CheckboxPrimitive.Root>, | ||
| React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> | ||
| >(({ className, children, ...props }, ref) => { | ||
| return ( | ||
| <Label className="flex cursor-pointer items-center gap-1"> | ||
| <CheckboxPrimitive.Root | ||
| ref={ref} | ||
| className={cn( | ||
| "h-6 w-6 rounded-sm", | ||
| "border-2 border-gray-300", | ||
| "data-[state=checked]:border-none data-[state=checked]:bg-bloom-orbit data-[state=checked]:text-primary-foreground", | ||
| "disabled:cursor-not-allowed disabled:opacity-50", | ||
| className, | ||
| )} | ||
| {...props} | ||
| > | ||
| <CheckboxPrimitive.Indicator className="flex items-center justify-center"> | ||
| <FaCheck className="h-4 w-4 text-white" /> | ||
| </CheckboxPrimitive.Indicator> | ||
| </CheckboxPrimitive.Root> | ||
| {children} | ||
| </Label> | ||
| ); | ||
| }); | ||
|
|
||
| Checkbox.displayName = "Checkbox"; | ||
|
|
||
| export { Checkbox }; | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "use client" directive is missing at the top of this file. Other similar Radix UI component files in this codebase (e.g., accordion.tsx, select.tsx) include this directive, which is necessary for components that use React hooks like useCallback and useContext in Next.js App Router.