'use client'
import { useState, useSyncExternalStore } from 'react'
import {
Avatar,
AvatarFallback,
AvatarImage,
Badge,
BubbleChatClose,
BubbleChatPreview,
Button,
ButtonGroup,
ButtonGroupItem,
Checkbox,
ChevronDown,
ChipDatePicker,
Code,
Combobox,
Connections,
Cursor,
DocumentAttachment,
Download,
Duplicate,
Expand,
Eye,
FolderCode,
FolderPlus,
Hand,
HexSimple,
Input,
Key as KeyIcon,
Label,
Layout,
Library,
Loader,
Modal,
ModalBody,
ModalContent,
ModalDescription,
ModalFooter,
ModalHeader,
ModalTabs,
ModalTabsContent,
ModalTabsList,
ModalTabsTrigger,
ModalTrigger,
MoreHorizontal,
NoWrap,
PanelLeft,
Play,
PlayOutline,
Popover,
PopoverBackButton,
PopoverContent,
PopoverFolder,
PopoverItem,
PopoverScrollArea,
PopoverSearch,
PopoverSection,
PopoverTrigger,
Redo,
Rocket,
Slider,
Switch,
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
TagInput,
type TagItem,
Textarea,
TimePicker,
ToastProvider,
Tooltip,
Trash,
Trash2,
toast,
Undo,
Wrap,
ZoomIn,
ZoomOut,
} from '@sim/emcn'
import { ArrowLeft, Folder, Moon, Sun } from 'lucide-react'
import { notFound, useRouter } from 'next/navigation'
import { env, isTruthy } from '@/lib/core/config/env'
function Section({ title, children }: { title: string; children: React.ReactNode }) {
return (
)
}
function VariantRow({ label, children }: { label: string; children: React.ReactNode }) {
return (
)
}
const SAMPLE_CODE = `function greet(name) {
console.log("Hello, " + name);
return { success: true };
}`
const SAMPLE_PYTHON = `def greet(name):
print(f"Hello, {name}")
return {"success": True}`
const COMBOBOX_OPTIONS = [
{ label: 'Option 1', value: 'opt1' },
{ label: 'Option 2', value: 'opt2' },
{ label: 'Option 3', value: 'opt3' },
]
const DARK_MODE_EVENT = 'playground:dark-mode-change'
const subscribeToDarkMode = (onStoreChange: () => void) => {
window.addEventListener(DARK_MODE_EVENT, onStoreChange)
return () => window.removeEventListener(DARK_MODE_EVENT, onStoreChange)
}
const getDarkModeSnapshot = () => document.documentElement.classList.contains('dark')
const getServerDarkModeSnapshot = () => false
export default function PlaygroundPage() {
const router = useRouter()
const [comboboxValue, setComboboxValue] = useState('')
const [switchValue, setSwitchValue] = useState(false)
const [checkboxValue, setCheckboxValue] = useState(false)
const [sliderValue, setSliderValue] = useState([50])
const [timeValue, setTimeValue] = useState('09:30')
const isDarkMode = useSyncExternalStore(
subscribeToDarkMode,
getDarkModeSnapshot,
getServerDarkModeSnapshot
)
const [buttonGroupValue, setButtonGroupValue] = useState('curl')
const [dateValue, setDateValue] = useState('')
const [dateRangeStart, setDateRangeStart] = useState('')
const [dateRangeEnd, setDateRangeEnd] = useState('')
const [tagItems, setTagItems] = useState([
{ value: 'user@example.com', isValid: true },
{ value: 'invalid-email', isValid: false, error: 'Invalid email format' },
])
const toggleDarkMode = () => {
document.documentElement.classList.toggle('dark')
window.dispatchEvent(new Event(DARK_MODE_EVENT))
}
if (!isTruthy(env.NEXT_PUBLIC_ENABLE_PLAYGROUND)) {
notFound()
}
return (
Go back
{isDarkMode ? 'Light mode' : 'Dark mode'}
EMCN Component Playground
All emcn UI components and their variants
{/* Toast */}
{/* Button */}
{/* ButtonGroup */}
cURL
Python
JavaScript
Option 1
Option 2
Option 1
Option 2
Option 1
Option 2
Only Option
{/* Badge */}
Default
Outline
Type
Green
With Dot
Red
With Dot
Blue
With Dot
Blue Secondary
Purple
Orange
Amber
Teal
Cyan
Gray
Gray Secondary
Small
Medium
Large
{/* Input */}
{/* TagInput */}
{
const isValid = value.includes('@') && value.includes('.')
setTagItems((prev) => [...prev, { value, isValid }])
return isValid
}}
onRemove={(_, index) => {
setTagItems((prev) => prev.filter((_, i) => i !== index))
}}
placeholder='Enter emails...'
placeholderWithTags='Add another'
/>
true}
onRemove={() => {}}
placeholder='Add tags'
placeholderWithTags='Add another'
triggerKeys={['Enter', ',']}
/>
false}
onRemove={() => {}}
placeholder='Disabled input'
disabled
/>
{/* Textarea */}
{/* Label */}
{/* Switch */}
{switchValue ? 'On' : 'Off'}
{/* Checkbox */}
setCheckboxValue(!!c)} />
{checkboxValue ? 'Checked' : 'Unchecked'}
Small (14px)
Medium (16px)
Large (20px)
{/* Slider */}
{/* Avatar */}
XS
SM
MD
LG
CN
JD
JD
JD
JD
XS
SM
MD
LG
{/* Table */}
Name
Status
Role
Alice
Active
Admin
Bob
Pending
User
Charlie
Active
User
Item
Price
Product A
$10.00
Product B
$20.00
Total
$30.00
A list of team members
Name
Department
Alice
Engineering
Bob
Design
{/* Combobox */}
{}}
placeholder='Small size'
size='sm'
/>
{}}
placeholder='With search'
searchable
/>
{}}
placeholder='Type or select...'
editable
/>
{}}
placeholder='Select multiple...'
multiSelect
searchable
/>
{/* TimePicker */}
{timeValue}
{}}
placeholder='Small size'
size='sm'
/>
{}} />
{/* ChipDatePicker */}
{dateValue || 'No date'}
{
setDateRangeStart(start)
setDateRangeEnd(end)
}}
placeholder='Select date range'
fullWidth
/>
{
setDateRangeStart(start)
setDateRangeEnd(end)
}}
placeholder='Select date range'
fullWidth
/>
{/* Tooltip */}
Tooltip content
Clear console
{/* Popover */}
Section Title
Item 1
Item 2
Active Item
Item 1
Active Item
Apple
Banana
Cherry
Date
Elderberry
Root Item
}
>
Nested Item 1
Nested Item 2
}
>
Another Nested Item
{/* Modal */}
{(['sm', 'md', 'lg', 'xl', 'full'] as const).map((size) => (
Modal {size.toUpperCase()}
This is a {size} sized modal.
))}
Settings
General
Advanced
Modal settings with general and advanced tabs
General settings content
Advanced settings content
{/* Code */}
{/* Icons */}
{[
{ Icon: BubbleChatClose, name: 'BubbleChatClose' },
{ Icon: BubbleChatPreview, name: 'BubbleChatPreview' },
{ Icon: ChevronDown, name: 'ChevronDown' },
{ Icon: Connections, name: 'Connections' },
{ Icon: Cursor, name: 'Cursor' },
{ Icon: DocumentAttachment, name: 'DocumentAttachment' },
{ Icon: Download, name: 'Download' },
{ Icon: Duplicate, name: 'Duplicate' },
{ Icon: Expand, name: 'Expand' },
{ Icon: Eye, name: 'Eye' },
{ Icon: FolderCode, name: 'FolderCode' },
{ Icon: FolderPlus, name: 'FolderPlus' },
{ Icon: Hand, name: 'Hand' },
{ Icon: HexSimple, name: 'HexSimple' },
{ Icon: KeyIcon, name: 'Key' },
{ Icon: Layout, name: 'Layout' },
{ Icon: Library, name: 'Library' },
{ Icon: Loader, name: 'Loader' },
{ Icon: MoreHorizontal, name: 'MoreHorizontal' },
{ Icon: NoWrap, name: 'NoWrap' },
{ Icon: PanelLeft, name: 'PanelLeft' },
{ Icon: Play, name: 'Play' },
{ Icon: PlayOutline, name: 'PlayOutline' },
{ Icon: Redo, name: 'Redo' },
{ Icon: Rocket, name: 'Rocket' },
{ Icon: Trash, name: 'Trash' },
{ Icon: Trash2, name: 'Trash2' },
{ Icon: Undo, name: 'Undo' },
{ Icon: Wrap, name: 'Wrap' },
{ Icon: ZoomIn, name: 'ZoomIn' },
{ Icon: ZoomOut, name: 'ZoomOut' },
].map(({ Icon, name }) => (
{name}
))}
)
}