mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
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:
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 }}>
|
||||
|
||||
+53
-21
@@ -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_>
|
||||
|
||||
+3
-4
@@ -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,
|
||||
|
||||
+68
-43
@@ -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
@@ -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
|
||||
|
||||
@@ -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'
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user