chore: migrate old <Checkbox /> usage to the new Shadcn component (#45211)

## Problem

We want to reduce the code we ship and maintain.

## Solution

Migrate old `<Checkbox />` usage to the new Shadcn component.
There's one visual change: no more green background or outline.

## Screenshots

### On `apps/www`

Before:
<img width="1095" height="772" alt="image"
src="https://github.com/user-attachments/assets/b14a0477-d8ac-4ae5-a1c3-63657609e4e5"
/>

After:
<img width="1085" height="766" alt="image"
src="https://github.com/user-attachments/assets/f4c2156c-38e1-4834-b013-e39b8c3dd76e"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Unified checkbox appearance and behavior across the app for consistent
toggles, labels, and interactions.

* **Bug Fixes**
* Fixed selection issues including shift-select edge cases and
click-propagation in lists; added ARIA labels for improved
accessibility.

* **Chores**
* Removed legacy checkbox implementation, associated styles, tests, and
deprecated theme entries.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Gildas Garcia authored and GitHub committed 2026-04-24 17:38:01 +02:00
1 parent f0746dbea8
commit 502c098d90
15 files changed
+261 -549

No files matched your search

@@ -5,7 +5,7 @@ import { ChevronsDown, ChevronsUp, Copy, Eye, FolderPlus, Upload } from 'lucide-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { toast } from 'sonner'
import {
Checkbox,
Checkbox_Shadcn_ as Checkbox,
cn,
ContextMenu_Shadcn_,
ContextMenuContent_Shadcn_,
@@ -143,16 +143,6 @@ export const FileExplorerColumn = ({
}
}
const SelectAllCheckbox = () => (
<Checkbox
label=""
className="-mt-0.5"
checked={columnFiles.length !== 0 && selectedFilesFromColumn.length === columnFiles.length}
disabled={columnFiles.length === 0}
onChange={() => onSelectAllItemsInColumn(index)}
/>
)
const getItemKey = useCallback(
(index: number) => {
const item = columnItems[index]
@@ -218,10 +208,24 @@ export const FileExplorerColumn = ({
>
{columnFiles.length > 0 ? (
<>
<SelectAllCheckbox />
<p className="text-sm text-foreground-light">
Select all {columnFiles.length} files
</p>
<div className="flex items-center space-x-2">
<Checkbox
id="checkbox-select-all"
className="-mt-0.5"
checked={
columnFiles.length !== 0 &&
selectedFilesFromColumn.length === columnFiles.length
}
disabled={columnFiles.length === 0}
onCheckedChange={() => onSelectAllItemsInColumn(index)}
/>
<label
htmlFor="checkbox-select-all"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Select all {columnFiles.length} files
</label>
</div>
</>
) : (
<p className="text-sm text-foreground-light">No files available for selection</p>
@@ -233,7 +237,24 @@ export const FileExplorerColumn = ({
{view === STORAGE_VIEWS.LIST && (
<div className="sticky top-0 py-2 z-10 flex min-w-min items-center border-b border-overlay bg-surface-100 px-2.5">
<div className="flex w-[40%] min-w-[250px] items-center">
<SelectAllCheckbox />
<div className="relative w-[30px]" onClick={(event) => event.stopPropagation()}>
<Checkbox
id="checkbox-select-all"
className="-mt-0.5"
checked={
columnFiles.length !== 0 &&
selectedFilesFromColumn.length === columnFiles.length
}
disabled={columnFiles.length === 0}
onCheckedChange={() => onSelectAllItemsInColumn(index)}
/>
<label
htmlFor="checkbox-select-all"
className="sr-only text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Select all {columnFiles.length} files
</label>
</div>
<p className="text-sm">Name</p>
</div>
<p className="w-[11%] min-w-[100px] text-sm">Size</p>
@@ -18,7 +18,7 @@ import {
} from 'lucide-react'
import type { CSSProperties } from 'react'
import {
Checkbox,
Checkbox_Shadcn_ as Checkbox,
cn,
DropdownMenu,
DropdownMenuContent,
@@ -333,15 +333,15 @@ export const FileExplorerRow = ({
</div>
)}
<Checkbox
label={''}
className={`w-full ${item.type !== STORAGE_ROW_TYPES.FILE ? 'invisible' : ''} ${
className={`${item.type !== STORAGE_ROW_TYPES.FILE ? 'invisible' : ''} ${
isSelected ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`}
checked={isSelected}
onChange={(event) => {
event.stopPropagation()
onCheckItem((event.nativeEvent as KeyboardEvent).shiftKey)
// use onClick instead of onCheckedChange to handle shift-key selection
onClick={(event) => {
onCheckItem(event.nativeEvent.shiftKey)
}}
aria-label="Check to select this item"
/>
</div>
<p title={item.name} className="truncate text-sm" style={{ width: nameWidth }}>
@@ -1,5 +1,5 @@
import { noop } from 'lodash'
import { Button, Checkbox, cn, Modal } from 'ui'
import { Button, Checkbox_Shadcn_ as Checkbox, cn, Modal } from 'ui'
import { STORAGE_CLIENT_LIBRARY_MAPPINGS } from '../Storage.constants'
import { deriveAllowedClientLibraryMethods } from '../Storage.utils'
@@ -52,26 +52,58 @@ const PolicyAllowedOperations = ({ allowedOperations = [], onToggleOperation = (
</div>
<div className="md:w-2/3 flex flex-col gap-3">
<div className="flex flex-wrap items-center gap-x-8 gap-y-4">
<Checkbox
label="SELECT"
onChange={() => onToggleOperation('SELECT')}
checked={allowedOperations.includes('SELECT')}
/>
<Checkbox
label="INSERT"
onChange={() => onToggleOperation('INSERT')}
checked={allowedOperations.includes('INSERT')}
/>
<Checkbox
label="UPDATE"
onChange={() => onToggleOperation('UPDATE')}
checked={allowedOperations.includes('UPDATE')}
/>
<Checkbox
label="DELETE"
onChange={() => onToggleOperation('DELETE')}
checked={allowedOperations.includes('DELETE')}
/>
<div className="flex items-center space-x-2">
<Checkbox
id="checkbox-select"
onCheckedChange={() => onToggleOperation('SELECT')}
checked={allowedOperations.includes('SELECT')}
/>
<label
htmlFor="checkbox-select"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
SELECT
</label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="checkbox-insert"
onCheckedChange={() => onToggleOperation('INSERT')}
checked={allowedOperations.includes('INSERT')}
/>
<label
htmlFor="checkbox-insert"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
INSERT
</label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="checkbox-update"
onCheckedChange={() => onToggleOperation('UPDATE')}
checked={allowedOperations.includes('UPDATE')}
/>
<label
htmlFor="checkbox-update"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
UPDATE
</label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="checkbox-delete"
onCheckedChange={() => onToggleOperation('DELETE')}
checked={allowedOperations.includes('DELETE')}
/>
<label
htmlFor="checkbox-delete"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
DELETE
</label>
</div>
</div>
{hasUpdateOrDelete && (
<p className="text-sm text-foreground-light mt-3 prose [&>code]:text-xs">
@@ -1,7 +1,13 @@
import { ExternalLink } from 'lucide-react'
import Link from 'next/link'
import { toast } from 'sonner'
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Button, Checkbox } from 'ui'
import {
Alert_Shadcn_,
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Button,
Checkbox_Shadcn_ as Checkbox,
} from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { useTableFilter } from '@/components/grid/hooks/useTableFilter'
@@ -216,12 +222,24 @@ const DeleteConfirmationDialogs = ({
<p className="text-sm text-foreground-light">
Are you sure you want to delete the selected column? This action cannot be undone.
</p>
<Checkbox
label="Drop column with cascade?"
description="Deletes the column and its dependent objects"
checked={isDeleteWithCascade}
onChange={() => snap.toggleConfirmationIsWithCascade()}
/>
<div className="items-top flex space-x-2">
<Checkbox
id="checkbox-cascade"
checked={isDeleteWithCascade}
onCheckedChange={() => snap.toggleConfirmationIsWithCascade()}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="checkbox-cascade"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Drop column with cascade?
</label>
<p className="text-sm text-foreground-muted">
Deletes the column and its dependent objects
</p>
</div>
</div>
{isDeleteWithCascade && (
<Alert_Shadcn_
variant="warning"
@@ -265,12 +283,24 @@ const DeleteConfirmationDialogs = ({
<p className="text-sm text-foreground-light">
Are you sure you want to delete the selected table? This action cannot be undone.
</p>
<Checkbox
label="Drop table with cascade?"
description="Deletes the table and its dependent objects"
checked={isDeleteWithCascade}
onChange={() => snap.toggleConfirmationIsWithCascade(!isDeleteWithCascade)}
/>
<div className="items-top flex space-x-2">
<Checkbox
id="checkbox-cascade"
checked={isDeleteWithCascade}
onCheckedChange={() => snap.toggleConfirmationIsWithCascade(!isDeleteWithCascade)}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="checkbox-cascade"
className="text-sm text-foreground-light leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Drop table with cascade?
</label>
<p className="text-sm text-foreground-muted">
Deletes the table and its dependent objects
</p>
</div>
</div>
{isDeleteWithCascade && (
<Alert_Shadcn_ variant="warning">
<AlertTitle_Shadcn_>
@@ -5,7 +5,6 @@ import { useState } from 'react'
import {
Badge,
Button,
Checkbox,
Checkbox_Shadcn_,
cn,
Command_Shadcn_,
@@ -284,10 +283,10 @@ export const Column = ({
</div>
</div>
<div className="w-[10%]">
<Checkbox
label=""
<Checkbox_Shadcn_
aria-label="Check to make this column a primary key"
checked={column.isPrimaryKey}
onChange={() => {
onCheckedChange={() => {
const updatedValue = !column.isPrimaryKey
onUpdateColumn({
isPrimaryKey: updatedValue,
@@ -2,7 +2,7 @@ import type { PostgresTable } from '@supabase/postgres-meta'
import { isEmpty, noop } from 'lodash'
import { useContext, useEffect, useMemo, useState } from 'react'
import { toast } from 'sonner'
import { Badge, Checkbox, Input, SidePanel } from 'ui'
import { Badge, Checkbox_Shadcn_, Input, SidePanel } from 'ui'
import { Admonition } from 'ui-patterns'
import { ConfirmationModal } from 'ui-patterns/Dialogs/ConfirmationModal'
@@ -371,26 +371,31 @@ export const TableEditor = ({
<SidePanel.Separator />
<SidePanel.Content className="space-y-10 py-6">
<Checkbox
id="enable-rls"
// @ts-ignore
label={
<div className="flex items-center space-x-2">
<div className="items-top flex space-x-2">
<Checkbox_Shadcn_
id="enable-rls"
checked={tableFields.isRLSEnabled}
onCheckedChange={() => {
// if isEnabled, show confirm modal to turn off
// if not enabled, allow turning on without modal confirmation
tableFields.isRLSEnabled
? setRlsConfirmVisible(true)
: onUpdateField({ isRLSEnabled: !tableFields.isRLSEnabled })
}}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="enable-rls"
className="text-sm text-foreground-light flex items-center space-x-2 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
<span>Enable Row Level Security (RLS)</span>
<Badge>Recommended</Badge>
</div>
}
description="Restrict access to your table by enabling RLS and writing Postgres policies."
checked={tableFields.isRLSEnabled}
onChange={() => {
// if isEnabled, show confirm modal to turn off
// if not enabled, allow turning on without modal confirmation
tableFields.isRLSEnabled
? setRlsConfirmVisible(true)
: onUpdateField({ isRLSEnabled: !tableFields.isRLSEnabled })
}}
size="medium"
/>
</label>
<p className="text-sm text-foreground-muted">
Restrict access to your table by enabling RLS and writing Postgres policies.
</p>
</div>
</div>
{tableFields.isRLSEnabled ? (
<Admonition
@@ -433,22 +438,32 @@ export const TableEditor = ({
)}
{realtimeEnabled && (
<Checkbox
id="enable-realtime"
label="Enable Realtime"
description="Broadcast changes on this table to authorized subscribers"
checked={tableFields.isRealtimeEnabled}
onChange={() => {
track('realtime_toggle_table_clicked', {
newState: tableFields.isRealtimeEnabled ? 'disabled' : 'enabled',
origin: 'tableSidePanel',
})
onUpdateField({
isRealtimeEnabled: !tableFields.isRealtimeEnabled,
})
}}
size="medium"
/>
<div className="items-top flex space-x-2">
<Checkbox_Shadcn_
id="enable-realtime"
checked={tableFields.isRealtimeEnabled}
onCheckedChange={() => {
track('realtime_toggle_table_clicked', {
newState: tableFields.isRealtimeEnabled ? 'disabled' : 'enabled',
origin: 'tableSidePanel',
})
onUpdateField({
isRealtimeEnabled: !tableFields.isRealtimeEnabled,
})
}}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="enable-realtime"
className="text-sm text-foreground-light flex items-center space-x-2 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Enable Realtime
</label>
<p className="text-sm text-foreground-muted">
Broadcast changes on this table to authorized subscribers.
</p>
</div>
</div>
)}
</SidePanel.Content>
@@ -474,14 +489,24 @@ export const TableEditor = ({
)}
{isDuplicating && (
<>
<Checkbox
id="duplicate-rows"
label="Duplicate table entries"
description="This will copy all the data in the table into the new table"
checked={isDuplicateRows}
onChange={() => setIsDuplicateRows(!isDuplicateRows)}
size="medium"
/>
<div className="items-top flex space-x-2">
<Checkbox_Shadcn_
id="duplicate-rows"
checked={isDuplicateRows}
onCheckedChange={() => setIsDuplicateRows(!isDuplicateRows)}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="duplicate-rows"
className="text-sm text-foreground-light flex items-center space-x-2 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Duplicate table entries
</label>
<p className="text-sm text-foreground-muted">
This will copy all the data in the table into the new table
</p>
</div>
</div>
</>
)}
@@ -3,7 +3,7 @@ import { useParams } from 'common'
import { ChangeEvent, useEffect, useState } from 'react'
import { AWS_REGIONS } from 'shared-data'
import { toast } from 'sonner'
import { Alert, Button, Checkbox, Input, Listbox } from 'ui'
import { Alert, Button, Checkbox_Shadcn_, Input, Listbox } from 'ui'
import { isVercelUrl } from '@/components/interfaces/Integrations/Vercel/VercelIntegration.utils'
import { Markdown } from '@/components/interfaces/Markdown'
@@ -306,22 +306,48 @@ const CreateProject = () => {
</div>
</div>
<div className="py-2 pb-4">
<Checkbox
name="shouldRunMigrations"
label="Create sample tables with seed data"
description="To get you started quickly, we can create new tables for you with seed (sample) data. You can delete these tables later."
checked={shouldRunMigrations}
onChange={(e) => setShouldRunMigrations(e.target.checked)}
/>
<div className="items-top flex space-x-2">
<Checkbox_Shadcn_
id="shouldRunMigrations"
name="shouldRunMigrations"
checked={shouldRunMigrations}
onCheckedChange={(checked) => setShouldRunMigrations(!!checked)}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="enable-realtime"
className="text-sm text-foreground-light flex items-center space-x-2 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Create sample tables with seed data
</label>
<p className="text-sm text-foreground-muted">
To get you started quickly, we can create new tables for you with seed (sample) data.
You can delete these tables later.
</p>
</div>
</div>
</div>
<div className="py-2 pb-4">
<Checkbox
name="dataApiDefaultPrivileges"
label="Automatically expose new tables and functions"
description="Grants privileges to Data API roles by default, exposing new tables and functions. We recommend disabling this to control access manually."
checked={dataApiDefaultPrivileges}
onChange={(e) => setDataApiDefaultPrivileges(e.target.checked)}
/>
<div className="items-top flex space-x-2">
<Checkbox_Shadcn_
id="dataApiDefaultPrivileges"
name="dataApiDefaultPrivileges"
checked={dataApiDefaultPrivileges}
onCheckedChange={(checked) => setDataApiDefaultPrivileges(!!checked)}
/>
<div className="grid gap-1.5 leading-none">
<label
htmlFor="dataApiDefaultPrivileges"
className="text-sm text-foreground-light flex items-center space-x-2 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Automatically expose new tables and functions
</label>
<p className="text-sm text-foreground-muted">
Grants privileges to Data API roles by default, exposing new tables and functions. We
recommend disabling this to control access manually.
</p>
</div>
</div>
</div>
<div className="flex flex-row w-full justify-end">
<Button
+10 -12
View File
@@ -1,17 +1,15 @@
import React, { useEffect, useState, useCallback } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/compat/router'
import { NextSeo } from 'next-seo'
import { motion } from 'framer-motion'
import { Search } from 'lucide-react'
import { debounce } from 'lib/helpers'
import { Button, Checkbox, cn, Input } from 'ui'
import DefaultLayout from '~/components/Layouts/Default'
import SectionContainer from '~/components/Layouts/SectionContainer'
import Panel from '~/components/Panel'
import { features } from '~/data/features'
import { motion } from 'framer-motion'
import { debounce } from 'lib/helpers'
import { Search } from 'lucide-react'
import { NextSeo } from 'next-seo'
import { useRouter } from 'next/compat/router'
import Link from 'next/link'
import React, { useCallback, useEffect, useState } from 'react'
import { Button, Checkbox_Shadcn_ as Checkbox, cn, Input } from 'ui'
function FeaturesPage() {
const router = useRouter()
@@ -139,7 +137,7 @@ function FeaturesPage() {
<Checkbox
id="self-hosted-filter"
checked={showSelfHostedOnly}
onChange={() => setShowSelfHostedOnly(!showSelfHostedOnly)}
onCheckedChange={() => setShowSelfHostedOnly(!showSelfHostedOnly)}
className="[&_input]:m-0"
/>
<label
@@ -163,7 +161,7 @@ function FeaturesPage() {
<Checkbox
id={product}
checked={selectedProducts.includes(product)}
onChange={() => handleProductChange(product)}
onCheckedChange={() => handleProductChange(product)}
className="[&_input]:m-0"
/>
<label
-1
View File
@@ -38,7 +38,6 @@ export * from './src/lib/utils'
export * from './src/components/Select'
export * from './src/components/Listbox'
export * from './src/components/Checkbox'
export * from './src/components/Input'
export * from './src/components/Toggle'
export * from './src/components/ExpandingTextArea'
@@ -1,127 +0,0 @@
/* clear native styling */
/* .sbui-checkbox[type='checkbox'] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
padding: 0;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
display: inline-block;
vertical-align: middle;
background-origin: border-box;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
flex-shrink: 0;
height: 1rem;
width: 1rem;
color: #2563eb;
background-color: #fff;
border-color: #6b7280;
border-width: 1px;
} */
/* .sbui-checkbox[type='checkbox']:checked {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
}
.sbui-checkbox[type='checkbox']:checked {
@apply dark:bg-brand-400;
@apply bg-brand-400;
border-color: transparent;
background-size: 100% 100%;
background-position: center;
background-repeat: no-repeat;
} */
/* .sbui-checkbox {
@apply border border-solid rounded;
@apply text-brand-400 border-gray-300 transition-all;
@apply hover:border-brand-300 focus:ring-brand-300 focus:outline-none;
@apply dark:bg-transparent dark:border-dark-400 dark:text-white;
@apply dark:hover:border-brand-300;
margin-top: 2px;
} */
/*
.sbui-checkbox-container {
@apply flex cursor-pointer;
} */
/* .sbui-checkbox__label-container {
@apply leading-none;
} */
/* .sbui-checkbox__label-container__label {
@apply text-gray-700 dark:text-white cursor-pointer mt-0;
}
.sbui-checkbox__label-container__label__span {
@apply font-medium;
}
.sbui-checkbox__label-container__label__span .sbui-checkbox__label-text-before,
.sbui-checkbox__label-container__label__span .sbui-checkbox__label-text-after {
@apply text-gray-400 dark:text-gray-300;
}
.sbui-checkbox__label-container__label__p {
@apply mt-0 text-gray-400 dark:text-gray-300;
} */
/*
Label sizes
*/
/* .sbui-checkbox-container--tiny .sbui-checkbox__label-container__label,
.sbui-checkbox-container--tiny .sbui-checkbox__label-container__label__span,
.sbui-checkbox-container--tiny .sbui-checkbox__label-container__label__p {
@apply text-xs;
}
.sbui-checkbox-container--small .sbui-checkbox__label-container__label,
.sbui-checkbox-container--small .sbui-checkbox__label-container__label__span,
.sbui-checkbox-container--small .sbui-checkbox__label-container__label__p {
@apply text-sm;
}
.sbui-checkbox-container--medium .sbui-checkbox__label-container__label,
.sbui-checkbox-container--medium .sbui-checkbox__label-container__label__span,
.sbui-checkbox-container--medium .sbui-checkbox__label-container__label__p {
@apply text-sm;
}
.sbui-checkbox-container--large .sbui-checkbox__label-container__label,
.sbui-checkbox-container--large .sbui-checkbox__label-container__label__span,
.sbui-checkbox-container--large .sbui-checkbox__label-container__label__p {
@apply text-base;
}
.sbui-checkbox-container--xlarge .sbui-checkbox__label-container__label,
.sbui-checkbox-container--xlarge .sbui-checkbox__label-container__label__span,
.sbui-checkbox-container--xlarge .sbui-checkbox__label-container__label__p {
@apply text-base;
} */
/*
Checkbox sizes
*/
/* .sbui-checkbox-container--tiny .sbui-checkbox {
@apply h-3 w-3 mt-1 mr-3;
}
.sbui-checkbox-container--small .sbui-checkbox {
@apply h-3.5 w-3.5 mt-0.5 mr-3.5;
}
.sbui-checkbox-container--medium .sbui-checkbox {
@apply h-4 w-4 mt-0.5 mr-3.5;
}
.sbui-checkbox-container--large .sbui-checkbox {
@apply h-5 w-5 mt-0.5 mr-4;
}
.sbui-checkbox-container--xlarge .sbui-checkbox {
@apply h-5 w-5 mt-0.5 mr-4;
} */
@@ -1,17 +0,0 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { describe, expect, it } from 'vitest'
import Checkbox from './Checkbox'
describe('#Checkbox', () => {
it('should render checkbox correctly', () => {
render(<Checkbox data-testid="form-checkbox" label="labelIsRequired" />)
expect(screen.queryByTestId('form-checkbox')).toBeInTheDocument()
})
it('should show label', () => {
render(<Checkbox data-testid="form-checkbox" label="JavaScript" />)
expect(screen.queryByText('JavaScript')).toBeInTheDocument()
})
})
@@ -1,201 +0,0 @@
'use client'
import React from 'react'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
import styleHandler from '../../lib/theme/styleHandler'
import CheckboxStyles from './Checkbox.module.css'
import { CheckboxContext } from './CheckboxContext'
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
afterLabel?: string
beforeLabel?: string
description?: string
label?: string
size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
}
interface GroupProps {
id?: string
layout?: 'horizontal' | 'vertical'
error?: any
descriptionText?: any
label?: any
afterLabel?: string
beforeLabel?: string
labelOptional?: any
name?: any
value?: any
className?: string
children?: React.ReactNode
options?: Array<InputProps>
defaultValue?: string
onChange?(x: React.ChangeEvent<HTMLInputElement>): void
size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
}
/**
* @deprecated Use `import { Checkbox_shadcn_ } from "ui"` instead
*/
function Group({
id,
layout = 'vertical',
error,
descriptionText,
label,
afterLabel,
beforeLabel,
labelOptional,
children,
className,
options,
onChange,
size = 'medium',
}: GroupProps) {
const parentCallback = (e: React.ChangeEvent<HTMLInputElement>) => {
if (onChange) onChange(e)
}
const __styles = styleHandler('checkbox')
return (
<FormLayout
label={label}
afterLabel={afterLabel}
beforeLabel={beforeLabel}
labelOptional={labelOptional}
layout={layout}
id={id}
error={error}
descriptionText={descriptionText}
className={className}
size={size}
>
<CheckboxContext.Provider value={{ parentCallback, parentSize: size }}>
<div className={__styles.group}>
{options
? options.map((option: InputProps) => {
return (
<Checkbox
id={option.id}
key={option.id}
value={option.value}
label={option.label}
beforeLabel={option.beforeLabel}
afterLabel={option.afterLabel}
checked={option.checked}
name={option.name}
description={option.description}
defaultChecked={option.defaultChecked}
/>
)
})
: children}
</div>
</CheckboxContext.Provider>
</FormLayout>
)
}
/**
* @deprecated Use ./Checkbox_shadcn_ instead
*/
export function Checkbox({
className,
id = '',
name = '',
label,
afterLabel,
beforeLabel,
description,
value,
onChange,
size = 'medium',
disabled = false,
...props
}: InputProps) {
const __styles = styleHandler('checkbox')
return (
<CheckboxContext.Consumer>
{({ parentCallback, parentSize }) => {
// if id does not exist, use label
const markupId = id
? id
: name
? name
: label
? label
.toLowerCase()
.replace(/^[^A-Z0-9]+/gi, '')
.replace(/ /g, '-')
: undefined
// @ts-ignore
size = parentSize ? parentSize : size
// if name does not exist on Radio then use Context Name from Radio.Group
// if that fails, use the id
const markupName = name ? name : markupId
let containerClasses = [__styles.container]
function onInputChange(e: React.ChangeEvent<HTMLInputElement>) {
// '`onChange` callback for parent component
if (parentCallback) parentCallback(e)
// '`onChange` callback for this component
if (onChange) onChange(e)
}
if (className) containerClasses.push(className)
return (
<div className={containerClasses.join(' ')}>
<input
id={markupId}
name={markupName}
type="checkbox"
className={[__styles.base, __styles.size[size]].join(' ')}
onChange={onInputChange}
value={value ? value : markupId}
disabled={disabled}
{...props}
/>
<label
className={[__styles.label.base, __styles.label[size]].join(' ')}
htmlFor={markupId}
>
<span>
{beforeLabel && (
<span
className={[__styles.label_before.base, __styles.label_before[size]].join(' ')}
>
{beforeLabel}
</span>
)}
{label}
{afterLabel && (
<span
className={[__styles.label_after.base, __styles.label_after[size]].join(' ')}
>
{afterLabel}
</span>
)}
</span>
{description && (
<p className={[__styles.description.base, __styles.description[size]].join(' ')}>
{description}
</p>
)}
</label>
</div>
)
}}
</CheckboxContext.Consumer>
)
}
Checkbox.Group = Group
export default Checkbox
@@ -1,10 +0,0 @@
'use client'
import { createContext } from 'react'
// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
export const CheckboxContext = createContext({
parentCallback: (e: any) => {},
parentSize: '',
})
@@ -1,4 +0,0 @@
import Checkbox from './Checkbox'
export default Checkbox
export { default as Checkbox } from './Checkbox'
-59
View File
@@ -511,65 +511,6 @@ export default {
chevron: 'h-5 w-5 text-foreground-lighter',
},
/*
* Checkbox
*
*
* This Checkbox requires a plugin in your config:
```
// tailwind.config.js
module.exports = {
// ...
plugins: [
// ...
require('@tailwindcss/forms'),
],
}
```
*
*
*/
checkbox: {
base: `
bg-transparent
${defaults.focus}
focus:ring-border-muted
text-brand
border-strong
shadow-sm
rounded
cursor-pointer
`,
container: `flex cursor-pointer leading-none`,
size: {
tiny: `h-3 w-3 mt-1 mr-3`,
small: `h-3.5 w-3.5 mt-0.5 mr-3.5`,
medium: `h-4 w-4 mt-0.5 mr-3.5`,
large: `h-5 w-5 mt-0.5 mr-4`,
xlarge: `h-5 w-5 mt-0.5 mr-4`,
},
disabled: 'opacity-50',
label: {
base: `text-foreground-light cursor-pointer`,
...defaults.size.text,
},
label_before: {
base: 'text-border',
...defaults.size.text,
},
label_after: {
base: 'text-border',
...defaults.size.text,
},
description: {
base: `text-foreground-lighter`,
...defaults.size.text,
},
group: `space-y-3`,
},
sidepanel: {
base: `
z-50