json-reactify
Version:
A comprehensive React component library for building dynamic forms, charts,sidebars and alerts from JSON configuration.
1,092 lines (912 loc) • 24.7 kB
Markdown
# json-reactify Documentation
A comprehensive React component library for building dynamic forms, charts,sidebars and alerts from JSON configuration.
---
## Form Component
The Form component is a flexible, type-safe React form builder that supports multiple field types with built-in validation using React Hook Form and Zod.
<details>
<summary><strong>Quick Start</strong></summary>
```tsx
import { Form } from 'json-reactify'
// Define your form schema
const userSchema = z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
age: z.number().min(18, 'Must be at least 18 years old'),
})
type UserFormData = z.infer<typeof userSchema>
// Configure your form fields
const formConfig = [
{
fieldType: FormFieldType.TEXT,
fieldName: 'name',
fieldLabel: 'Full Name',
placeholder: 'Enter your full name',
description: 'Your legal first and last name',
},
{
fieldType: FormFieldType.EMAIL,
fieldName: 'email',
fieldLabel: 'Email Address',
placeholder: 'you@example.com',
},
{
fieldType: FormFieldType.NUMBER,
fieldName: 'age',
fieldLabel: 'Age',
placeholder: '25',
},
]
// Use the component
function MyForm() {
const handleSubmit = (data: UserFormData) => {
console.log('Form submitted:', data)
}
return (
<Form
formConfig={formConfig}
schema={userSchema}
onSubmit={handleSubmit}
defaultValues={{ name: '', email: '', age: 0 }}
/>
)
}
```
</details>
<details>
<summary><strong>Field Types</strong></summary>
### Text Input Fields
```tsx
{
fieldType: FormFieldType.TEXT,
fieldName: 'username',
fieldLabel: 'Username',
placeholder: 'Enter username',
icon: User, // Optional icon from lucide-react
}
```
**Supported types:** `TEXT`, `PASSWORD`, `EMAIL`, `NUMBER`
### Textarea
```tsx
{
fieldType: FormFieldType.TEXTAREA,
fieldName: 'description',
fieldLabel: 'Description',
placeholder: 'Enter description...',
rows: 4,
}
```
### Checkbox
```tsx
{
fieldType: FormFieldType.CHECKBOX,
fieldName: 'agreeToTerms',
fieldLabel: 'I agree to the terms and conditions',
description: 'You must agree to continue',
}
```
### Switch
```tsx
{
fieldType: FormFieldType.SWITCH,
fieldName: 'notifications',
fieldLabel: 'Enable Notifications',
description: 'Receive email notifications',
}
```
### Select Dropdown
```tsx
{
fieldType: FormFieldType.SELECT,
fieldName: 'country',
fieldLabel: 'Country',
placeholder: 'Select your country',
options: [
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
{ value: 'uk', label: 'United Kingdom' },
],
}
```
### Radio Group
```tsx
{
fieldType: FormFieldType.RADIO,
fieldName: 'plan',
fieldLabel: 'Subscription Plan',
options: [
{ value: 'basic', label: 'Basic ($9/month)' },
{ value: 'pro', label: 'Pro ($19/month)' },
{ value: 'enterprise', label: 'Enterprise ($49/month)' },
],
orientation: 'vertical', // or 'horizontal'
}
```
### Combobox (Searchable Select)
```tsx
{
fieldType: FormFieldType.COMBOBOX,
fieldName: 'language',
fieldLabel: 'Programming Language',
placeholder: 'Select a language',
searchPlaceholder: 'Search languages...',
emptyMessage: 'No language found.',
options: [
{ value: 'js', label: 'JavaScript', icon: Code },
{ value: 'ts', label: 'TypeScript', icon: Code },
{ value: 'py', label: 'Python', icon: Code },
],
}
```
### Multi-Select
```tsx
{
fieldType: FormFieldType.MULTISELECT,
fieldName: 'skills',
fieldLabel: 'Skills',
placeholder: 'Select your skills',
maxSelectedDisplay: 3,
options: [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue.js' },
{ value: 'angular', label: 'Angular' },
{ value: 'node', label: 'Node.js' },
],
}
```
### Date Picker
```tsx
{
fieldType: FormFieldType.DATE,
fieldName: 'birthDate',
fieldLabel: 'Birth Date',
mode: 'single', // 'single', 'multiple', or 'range'
fromDate: new Date(1900, 0, 1),
toDate: new Date(),
}
```
### DateTime Picker
```tsx
{
fieldType: FormFieldType.DATETIME,
fieldName: 'appointmentTime',
fieldLabel: 'Appointment Date & Time',
timeFormat: '12', // '12' or '24'
timeStructure: 'hh:mm', // 'hh', 'hh:mm', or 'hh:mm:ss'
fromDate: new Date(),
toDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days from now
}
```
### File Upload
```tsx
{
fieldType: FormFieldType.FILE,
fieldName: 'avatar',
fieldLabel: 'Profile Picture',
accept: 'image/*',
multiple: false,
icon: Upload,
}
```
</details>
<details>
<summary><strong>Advanced Features</strong></summary>
### Conditional Fields
Show/hide fields based on other field values:
```tsx
{
fieldType: FormFieldType.TEXT,
fieldName: 'otherReason',
fieldLabel: 'Please specify',
showIf: (formValues) => formValues.reason === 'other',
dependsOn: ['reason'],
}
```
### Field Validation
Use Zod for powerful validation:
```tsx
const schema = z.object({
password: z.string().min(8, 'Password must be at least 8 characters'),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["confirmPassword"],
})
```
### Event Callbacks
Handle field-level events:
```tsx
{
fieldType: FormFieldType.EMAIL,
fieldName: 'email',
fieldLabel: 'Email',
onChangeField: (value) => {
console.log('Email changed:', value)
},
onBlurField: (value) => {
// Validate email exists
checkEmailExists(value)
},
onErrorField: (error) => {
console.error('Email field error:', error)
},
}
```
### Custom Submit Button
```tsx
<Form
formConfig={formConfig}
schema={schema}
onSubmit={handleSubmit}
customSubmitButton={
<div className="flex gap-2">
<Button type="submit" className="bg-blue-600">
Save Changes
</Button>
</div>
}
/>
```
</details>
<details>
<summary><strong>Props Reference</strong></summary>
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `formConfig` | `FormFieldConfig[]` | ✅ | Array of field configurations |
| `onSubmit` | `SubmitHandler<T>` | ✅ | Form submission handler |
| `schema` | `z.ZodSchema<T>` | ✅ | Zod validation schema |
| `defaultValues` | `DefaultValues<T>` | ❌ | Default form values |
| `customSubmitButton` | `React.ReactNode` | ❌ | Custom submit button component |
| `className` | `string` | ❌ | CSS classes for form container |
| `loading` | `boolean` | ❌ | Show loading skeletons |
### Field Configuration Options
All field types support these common properties:
| Property | Type | Description |
|----------|------|-------------|
| `fieldType` | `FormFieldType` | The type of field to render |
| `fieldName` | `string` | Field name (must match schema) |
| `fieldLabel` | `string` | Display label for the field |
| `description` | `string` | Optional help text |
| `placeholder` | `string` | Placeholder text |
| `disabled` | `boolean` | Disable the field |
| `hidden` | `boolean` | Hide the field |
| `showIf` | `(values) => boolean` | Conditional visibility |
| `dependsOn` | `string[]` | Fields this depends on |
| `onChangeField` | `(value) => void` | Change event handler |
| `onBlurField` | `(value) => void` | Blur event handler |
| `onErrorField` | `(error) => void` | Error event handler |
</details>
<details>
<summary><strong>Complete Example</strong></summary>
```tsx
import { Form, FormFieldType, FormOption } from 'json-reactify'
import * as z from 'zod'
import { User, Mail, Phone, MapPin } from 'lucide-react'
const profileSchema = z.object({
firstName: z.string().min(2, 'First name required'),
lastName: z.string().min(2, 'Last name required'),
email: z.string().email('Invalid email'),
phone: z.string().optional(),
country: z.string().min(1, 'Please select a country'),
bio: z.string().max(500, 'Bio must be under 500 characters').optional(),
skills: z.array(z.string()).min(1, 'Select at least one skill'),
availability: z.enum(['full-time', 'part-time', 'contract']),
newsletter: z.boolean(),
profilePicture: z.instanceof(File).optional(),
})
type ProfileFormData = z.infer<typeof profileSchema>
const countryOptions: FormOption[] = [
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'de', label: 'Germany' },
]
const skillOptions: FormOption[] = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue.js' },
{ value: 'angular', label: 'Angular' },
{ value: 'node', label: 'Node.js' },
{ value: 'python', label: 'Python' },
{ value: 'java', label: 'Java' },
]
const formConfig = [
{
fieldType: FormFieldType.TEXT,
fieldName: 'firstName',
fieldLabel: 'First Name',
placeholder: 'John',
icon: User,
},
{
fieldType: FormFieldType.TEXT,
fieldName: 'lastName',
fieldLabel: 'Last Name',
placeholder: 'Doe',
icon: User,
},
{
fieldType: FormFieldType.EMAIL,
fieldName: 'email',
fieldLabel: 'Email Address',
placeholder: 'john@example.com',
icon: Mail,
},
{
fieldType: FormFieldType.TEXT,
fieldName: 'phone',
fieldLabel: 'Phone Number',
placeholder: '+1 (555) 123-4567',
icon: Phone,
},
{
fieldType: FormFieldType.SELECT,
fieldName: 'country',
fieldLabel: 'Country',
placeholder: 'Select your country',
options: countryOptions,
icon: MapPin,
},
{
fieldType: FormFieldType.TEXTAREA,
fieldName: 'bio',
fieldLabel: 'Bio',
placeholder: 'Tell us about yourself...',
rows: 4,
description: 'Optional: Share a brief description about yourself',
},
{
fieldType: FormFieldType.MULTISELECT,
fieldName: 'skills',
fieldLabel: 'Skills',
placeholder: 'Select your skills',
options: skillOptions,
maxSelectedDisplay: 3,
},
{
fieldType: FormFieldType.RADIO,
fieldName: 'availability',
fieldLabel: 'Availability',
options: [
{ value: 'full-time', label: 'Full-time' },
{ value: 'part-time', label: 'Part-time' },
{ value: 'contract', label: 'Contract' },
],
},
{
fieldType: FormFieldType.SWITCH,
fieldName: 'newsletter',
fieldLabel: 'Newsletter Subscription',
description: 'Receive updates and news via email',
},
{
fieldType: FormFieldType.FILE,
fieldName: 'profilePicture',
fieldLabel: 'Profile Picture',
accept: 'image/*',
description: 'Upload a profile picture (optional)',
},
]
export default function ProfileForm() {
const handleSubmit = (data: ProfileFormData) => {
console.log('Profile data:', data)
// Handle form submission
}
const defaultValues: Partial<ProfileFormData> = {
firstName: '',
lastName: '',
email: '',
country: '',
skills: [],
availability: 'full-time',
newsletter: false,
}
return (
<div className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Create Profile</h1>
<Form
formConfig={formConfig}
schema={profileSchema}
onSubmit={handleSubmit}
defaultValues={defaultValues}
className="space-y-4"
/>
</div>
)
}
```
</details>
---
## Chart Component
A flexible React chart component built with Recharts and shadcn/ui. Supports multiple chart types, zoom, export, and table view.
<details>
<summary><strong>Features</strong></summary>
- **6 Chart Types**: Area, Line, Bar, Pie, Donut, Table
- **Interactive**: Zoom, click handlers, type switching
- **Responsive**: Auto-sizing and mobile-friendly
- **Export**: CSV download functionality
- **Customizable**: Themes, colors, styling
</details>
<details>
<summary><strong>Quick Start</strong></summary>
```tsx
import { Chart } from 'json-reactify'
const data = [
{ name: 'Jan', sales: 4000, revenue: 2400 },
{ name: 'Feb', sales: 3000, revenue: 1398 },
{ name: 'Mar', sales: 2000, revenue: 9800 },
]
<Chart
title="Sales Dashboard"
data={data}
chartType="line"
xAxisKey="name"
yAxisKeys={['sales', 'revenue']}
/>
```
</details>
<details>
<summary><strong>Chart Types</strong></summary>
```tsx
// Line Chart
<Chart chartType="line" data={data} xAxisKey="date" yAxisKeys={['value']} />
// Bar Chart
<Chart chartType="bar" data={data} xAxisKey="category" yAxisKeys={['amount']} />
// Pie Chart
<Chart chartType="pie" data={data} xAxisKey="name" yAxisKeys={['value']} />
// Table View
<Chart
chartType="table"
data={data}
tableConfig={{ sortable: true, showRowNumbers: true }}
/>
```
</details>
<details>
<summary><strong>Customization</strong></summary>
```tsx
<Chart
data={data}
config={{
sales: { label: 'Sales', color: '#8884d8' },
revenue: { label: 'Revenue', color: '#82ca9d' }
}}
pieColors={['#8884d8', '#82ca9d', '#ffc658']}
autoSize={{ minHeight: 300, maxHeight: 600 }}
zoom={{ enabled: true, showControls: true }}
onDataPointClick={(data) => console.log('Clicked:', data)}
/>
```
</details>
<details>
<summary><strong>Examples</strong></summary>
/>
```
</details>
<details>
<summary><strong>Props Reference</strong></summary>
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `data` | `ChartDataPoint[]` | `[]` | Chart data |
| `chartType` | `'area' \| 'line' \| 'bar' \| 'pie' \| 'donut' \| 'table'` | `'line'` | Chart type |
| `xAxisKey` | `string` | `'name'` | X-axis data key |
| `yAxisKeys` | `string[]` | `['value']` | Y-axis data keys |
| `title` | `ReactNode` | - | Chart title |
| `showTypeSelector` | `boolean` | `true` | Show type dropdown |
| `showDownload` | `boolean` | `true` | Show download button |
| `zoom` | `ZoomConfig` | - | Zoom configuration |
| `tableConfig` | `TableConfig` | - | Table settings |
| `onDataPointClick` | `(data) => void` | - | Click handler |
</details>
<details>
<summary><strong>💡 Examples</strong></summary>
### Dashboard Widget
```tsx
<Chart
title="Revenue"
data={revenueData}
chartType="area"
height={200}
showTypeSelector={false}
/>
```
### Interactive Report
```tsx
const [chartType, setChartType] = useState('bar')
<Chart
data={salesData}
chartType={chartType}
onChartTypeChange={setChartType}
onDataPointClick={(data) => setSelected(data)}
/>
```
### Sortable Table
```tsx
<Chart
chartType="table"
data={tableData}
tableConfig={{
sortable: true,
columnHeaders: { sales: 'Sales ($)' },
cellRenderer: (value, key) =>
key === 'sales' ? `$${value.toLocaleString()}` : value
}}
/>
```
</details>
<details>
<summary><strong>TypeScript Support</strong></summary>
```tsx
import type { ChartType, ChartDataPoint } from 'json-reactify'
interface MyData extends ChartDataPoint {
date: string
value: number
}
```
</details>
---
## Alert Service
A simple alert/notification system with auto-dismiss and TypeScript support.
```tsx
import { AlertProvider, useAlert } from 'json-reactify'
// 1. Wrap your app
function App() {
return (
<AlertProvider>
<MyComponent />
</AlertProvider>
)
}
// 2. Use in components
function MyComponent() {
const { showAlert } = useAlert()
const handleSuccess = () => {
showAlert('default', 'Success!', 'Action completed successfully.')
}
const handleError = () => {
showAlert('destructive', 'Error!', 'Something went wrong.')
}
return (
<div>
<button onClick={handleSuccess}>Success</button>
<button onClick={handleError}>Error</button>
</div>
)
}
```
**Available Methods:**
- `showAlert(type, title, description)` - Show alert (auto-dismisses in 3s)
- `closeAlert(id)` - Manually close alert
- `alerts` - Array of current alerts
**Alert Types:** `'default'` | `'destructive'`
---
## Sidebar Component
A flexible, configurable sidebar component system built with React and TypeScript that allows you to create dynamic navigation sidebars from JSON configuration.
<details>
<summary><strong>Installation</strong></summary>
```bash
npm install json-reactify
```
</details>
<details>
<summary><strong>Quick Start</strong></summary>
```tsx
import { Sidebar, SideBarProvider } from 'json-reactify'
import { Home, Settings, Users } from 'lucide-react'
function App() {
const sidebarConfig = {
groups: [
{
id: 'main',
label: 'Navigation',
items: [
{
id: 'home',
title: 'Home',
icon: Home,
url: '/'
},
{
id: 'users',
title: 'Users',
icon: Users,
url: '/users'
}
]
}
]
}
return (
<SideBarProvider>
<div className="flex">
<Sidebar config={sidebarConfig} />
<main className="flex-1 p-6">
{/* Your main content */}
</main>
</div>
</SideBarProvider>
)
}
```
</details>
<details>
<summary><strong>Components</strong></summary>
### Sidebar
The main sidebar component that renders a configurable navigation menu.
```tsx
import { Sidebar } from 'json-reactify'
<Sidebar
config={sidebarConfig}
enableSearch={true}
isLoading={false}
/>
```
#### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `config` | `SidebarConfig` | **required** | Configuration object defining the sidebar structure |
| `enableSearch` | `boolean` | `true` | Enable/disable search functionality |
| `isLoading` | `boolean` | `false` | Show loading skeleton when true |
### SideBarProvider
A provider component that wraps your application to provide sidebar context.
```tsx
import { SideBarProvider } from 'json-reactify'
<SideBarProvider>
<App />
</SideBarProvider>
```
</details>
<details>
<summary><strong> Configuration</strong></summary>
### SidebarConfig
The main configuration object that defines your sidebar structure.
```tsx
interface SidebarConfig {
groups: SidebarGroup[]
header?: ReactNode | SidebarHeaderConfig | SidebarGroup[]
footer?: ReactNode | SidebarFooterConfig | SidebarGroup[]
}
```
### SidebarGroup
Defines a group of related sidebar items.
```tsx
interface SidebarGroup {
id: string | number
label?: string
items: SidebarItem[]
}
```
### SidebarItem
Defines an individual sidebar menu item.
```tsx
interface SidebarItem {
id: string | number
title: string
icon?: React.ElementType | React.ReactNode
url?: string
onClick?: () => void
badge?: ReactNode | string | number
subItems?: SidebarSubItem[]
disabled?: boolean
defaultOpen?: boolean
showIf?: boolean | (() => boolean)
}
```
### SidebarSubItem
Defines a sub-item within a sidebar item (for nested menus).
```tsx
interface SidebarSubItem {
id: string | number
title: string
icon?: React.ElementType | React.ReactNode
url?: string
onClick?: () => void
badge?: ReactNode | string | number
disabled?: boolean
showIf?: boolean | (() => boolean)
}
```
### SidebarHeaderConfig
Configuration for the sidebar header section.
```tsx
interface SidebarHeaderConfig {
logo?: {
text?: string
iconUrl?: string
iconComponent?: React.ElementType
}
user?: {
name?: string
email?: string
avatarUrl?: string
avatarComponent?: React.ElementType
}
className?: string
}
```
### SidebarFooterConfig
Configuration for the sidebar footer section.
```tsx
interface SidebarFooterConfig {
buttons?: Array<{
id: string | number
label: string
icon?: React.ElementType
onClick?: () => void
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
}>
className?: string
}
```
</details>
<details>
<summary><strong> Examples</strong></summary>
### Basic Sidebar
```tsx
const basicConfig = {
groups: [
{
id: 'main',
label: 'Main Navigation',
items: [
{
id: 'dashboard',
title: 'Dashboard',
icon: LayoutDashboard,
url: '/dashboard'
},
{
id: 'analytics',
title: 'Analytics',
icon: BarChart,
url: '/analytics',
badge: 'New'
}
]
}
]
}
```
### Sidebar with Header and Footer
```tsx
const configWithHeaderFooter = {
groups: [
// ... your groups
],
header: {
logo: {
text: 'MyApp',
iconComponent: Logo
},
user: {
name: 'John Doe',
email: 'john@example.com',
avatarUrl: '/avatar.jpg'
}
},
footer: {
buttons: [
{
id: 'settings',
label: 'Settings',
icon: Settings,
onClick: () => navigate('/settings')
},
{
id: 'logout',
label: 'Logout',
icon: LogOut,
variant: 'destructive',
onClick: handleLogout
}
]
}
}
```
### Nested Menu Items
```tsx
const nestedConfig = {
groups: [
{
id: 'management',
label: 'Management',
items: [
{
id: 'users',
title: 'User Management',
icon: Users,
defaultOpen: true,
subItems: [
{
id: 'all-users',
title: 'All Users',
url: '/users'
},
{
id: 'user-roles',
title: 'User Roles',
url: '/users/roles'
},
{
id: 'permissions',
title: 'Permissions',
url: '/users/permissions'
}
]
}
]
}
]
}
```
### Conditional Items
```tsx
const conditionalConfig = {
groups: [
{
id: 'admin',
label: 'Admin',
items: [
{
id: 'admin-panel',
title: 'Admin Panel',
icon: Shield,
url: '/admin',
showIf: () => user?.role === 'admin'
},
{
id: 'beta-features',
title: 'Beta Features',
icon: Zap,
url: '/beta',
showIf: user?.betaAccess === true,
badge: 'Beta'
}
]
}
]
}
```
### Custom Header Component
```tsx
const CustomHeader = () => (
<div className="flex flex-col items-center p-4">
<img src="/logo.png" alt="Logo" className="w-8 h-8 mb-2" />
<h2 className="text-lg font-bold">My Application</h2>
</div>
)
const customHeaderConfig = {
groups: [
// ... your groups
],
header: <CustomHeader />
}
```
### With Search Functionality
```tsx
<Sidebar
config={sidebarConfig}
enableSearch={true} // Search is enabled by default
/>
```
The search functionality automatically indexes all sidebar items and sub-items, allowing users to quickly find and navigate to specific pages.
### Loading State
```tsx
<Sidebar
config={sidebarConfig}
isLoading={loading}
/>
```
When `isLoading` is true, the sidebar displays a skeleton loading state.
</details>
<details>
<summary><strong>✨ Features</strong></summary>
- **Fully Customizable** - Configure every aspect through JSON
- **Built-in Search** - Automatic search functionality across all menu items
- **Responsive Design** - Collapsible sidebar with icon-only mode
- **TypeScript Support** - Full type safety and IntelliSense
- **Flexible Icons** - Support for icon components or custom React nodes
- **Conditional Rendering** - Show/hide items based on conditions
- **Badges & Notifications** - Add badges to highlight important items
- **Nested Menus** - Support for multi-level navigation
- **Loading States** - Built-in skeleton loading animation
- **Theming** - Works with your existing CSS/Tailwind theme
</details>