@hero-dynamic-form/client
v1.0.51
Published
React components library for Hero Dynamic Forms with Tailwind CSS support.
Maintainers
Readme
@hero-dynamic-form/client
React components library for Hero Dynamic Forms with Tailwind CSS support.
Installation
npm install @hero-dynamic-form/client
# or
pnpm add @hero-dynamic-form/client
# or
yarn add @hero-dynamic-form/clientSetup
This library uses Tailwind CSS Preset approach (Solution 3), which means:
- Components are exported with Tailwind classes (NOT pre-compiled CSS)
- Consumer projects can customize the theme via their own
tailwind.config.js - Tailwind will scan and generate CSS at build time
1. Configure Tailwind CSS
In your project's tailwind.config.js:
const colors = require('tailwindcss/colors');
module.exports = {
// Import preset to get theme (colors, fonts, etc.)
presets: [
require('@hero-dynamic-form/client/tailwind-preset')
],
// ⚠️ IMPORTANT: Must include package dist in content paths
// Tailwind needs to scan package components for classes
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'./node_modules/@hero-dynamic-form/client/dist/**/*.js'
],
// Optional: Override or extend theme
theme: {
extend: {
colors: {
// Example: Change primary color
primary: colors.red, // Instead of default indigo
},
},
},
}Why this works:
- ✅ Preset provides theme - Custom colors (
primary,bodydark, etc.), fonts, fontSize - ✅ Preset provides plugins -
@tailwindcss/formsand@tailwindcss/typographyincluded - ✅ You control content paths - Scan your source + package dist
- ✅ You can override - Extend or override any theme values
Without Preset (Not Recommended):
If you don't want to use the preset, you must manually copy all theme configuration (50+ lines of colors, fontSize, etc.) and add plugins yourself.
2. Import Components
import { Button, Card } from '@hero-dynamic-form/client';
function App() {
return (
<div>
<Button variant="primary" size="md">
Click me
</Button>
<Card title="My Card">
Card content here
</Card>
</div>
);
}Why Use Preset?
Benefits of Using Preset
✅ Get theme automatically - No need to copy-paste complex config
✅ Easy to override - Only override values you want to change
✅ Always in sync - When package updates theme, you automatically get updates
✅ Simplified config - Your config file is short and maintainable
✅ Plugins included - @tailwindcss/forms and @tailwindcss/typography ready
Preset vs Manual Config
| Feature | With Preset | Manual Config | |---------|-------------|---------------| | Config complexity | 🟢 Simple (~10 lines) | 🔴 Complex (~60+ lines) | | Theme values | 🟢 Auto included | 🔴 Must copy manually | | Theme sync | 🟢 Auto sync | 🔴 Manual updates | | Override colors | 🟢 Override only what you need | 🔴 Define everything | | Plugins | 🟢 Included | 🔴 Must add manually |
How It Works
Tailwind CSS Configuration Strategy
This package uses Giải pháp 3: Tailwind Plugin/Preset approach:
Components are NOT pre-compiled - They export React components with Tailwind classes like
bg-primary-600,text-white, etc.Consumer's Tailwind scans the package - Via the
contentconfiguration, Tailwind will scannode_modules/@hero-dynamic-form/client/**/*.{js,tsx}to find all Tailwind classes used.CSS is generated at consumer's build time - When consumer runs their build, Tailwind generates CSS based on:
- Classes found in consumer's code
- Classes found in
@hero-dynamic-form/clientcomponents - Theme configuration from consumer's
tailwind.config.js
Benefits
✅ Consumer can customize theme - Change colors, fonts, spacing, etc. via their own config
✅ Automatic CSS purging - Only CSS for classes actually used will be generated
✅ No CSS bloat - No pre-compiled CSS file included in the package
✅ Consistent with existing patterns - Same approach as @hero-dynamic-form/core
Example: Changing Primary Color
If consumer changes their config:
// example/tailwind.config.js
theme: {
extend: {
colors: {
primary: colors.red, // Changed from indigo to red
}
}
}All components using bg-primary-600, text-primary-500, etc. will automatically use red colors instead of indigo!
Proof:
/* Before (with primary: colors.indigo) */
.bg-primary-600 {
background-color: rgb(79 70 229); /* Indigo */
}
/* After (with primary: colors.red) */
.bg-primary-600 {
background-color: rgb(220 38 38); /* Red */
}Components
Button
import { Button } from '@hero-dynamic-form/client';
<Button variant="primary" size="md" onClick={() => console.log('clicked')}>
Click me
</Button>Props:
variant?: 'primary' | 'secondary' | 'danger'- Button style variantsize?: 'sm' | 'md' | 'lg'- Button sizechildren: React.ReactNode- Button content- All standard HTML button attributes
Card
import { Card } from '@hero-dynamic-form/client';
<Card title="Card Title" className="mt-4">
<p>Card content goes here</p>
</Card>Props:
title?: string- Optional card titlechildren: React.ReactNode- Card contentclassName?: string- Additional CSS classes
Toast Notifications
Built-in toast notifications using react-toastify:
import { toast } from '@hero-dynamic-form/client';
// Success notification
toast.success('Created', 'Record has been created successfully');
// Error notification
toast.error('Error', 'Something went wrong');
// Info notification
toast.info('Info', 'FYI message');
// Warning notification
toast.warning('Warning', 'Be careful');
// Custom toast with component
toast.custom(<MyCustomComponent />);Toast is automatically included in the Application component. To customize:
<Application
schemas={schemas}
clientConfig={config}
uiConfig={{
toast: {
position: 'top-right', // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
autoClose: 3000, // milliseconds or false
theme: 'colored', // 'light' | 'dark' | 'colored'
}
}}
/>UI Configuration & Icon Overrides
The UIProvider allows customization of icons and UI elements. Icons can be overridden at multiple levels:
Icon Override Priority
defaults < schemaIcons < uiConfig.icons < runtimeBuilt-in Icons
The following icons are available by default:
| Key | Default Icon | Usage |
|-----|--------------|-------|
| back | ArrowLeftIcon | Back buttons |
| create | PlusIcon | Create/Add buttons |
| edit | PencilIcon | Edit buttons |
| delete | TrashIcon | Delete buttons |
| view | EyeIcon | View buttons |
| success | CheckCircleIcon | Success toasts |
| error | ExclamationCircleIcon | Error toasts |
| info | InformationCircleIcon | Info toasts |
| warning | ExclamationTriangleIcon | Warning toasts |
| settings | CogIcon | Settings |
| document | DocumentIcon | Documents |
Override Icons via uiConfig
import { Application } from '@hero-dynamic-form/client';
import { ArrowUturnLeftIcon, StarIcon } from '@heroicons/react/24/solid';
<Application
schemas={schemas}
clientConfig={config}
uiConfig={{
icons: {
back: ArrowUturnLeftIcon, // Override default back icon
create: StarIcon, // Override default create icon
myCustomAction: MyCustomIcon, // Add new custom icon
}
}}
/>Schema-Level Icons
Schemas can define their own icons (e.g., for custom actions):
const userSchema = {
resourceName: 'users',
name: 'User',
// Schema-level icon map
icons: {
approve: ApproveIcon,
reject: RejectIcon,
},
actions: [
{
name: 'approve',
type: 'record',
method: 'POST',
icon: ApproveIcon, // Action-specific icon
}
]
};Using Icons in Components
import { useUI } from '@hero-dynamic-form/client';
function MyComponent() {
const { getIcon, hasIcon } = useUI();
// Get icon with fallback
const BackIcon = getIcon('back');
const CustomIcon = getIcon('myCustomAction', DefaultFallback);
// Check if icon exists
if (hasIcon('approve')) {
const ApproveIcon = getIcon('approve');
}
return (
<button>
<BackIcon className="h-4 w-4 mr-1" />
Back
</button>
);
}Runtime Icon Registration
import { useUI } from '@hero-dynamic-form/client';
function MyComponent() {
const { registerIcons } = useUI();
useEffect(() => {
// Register icons at runtime
registerIcons({
dynamicIcon: DynamicIcon,
anotherIcon: AnotherIcon,
});
}, []);
}Exported Types
import type {
UIConfig,
UIProviderProps,
IconType,
IconMap,
BuiltInIconType,
} from '@hero-dynamic-form/client';CLI Tool - Quick Start
Initialize a New Project
One command to create a complete admin panel with auto-generated CRUD API:
# Create new project folder
mkdir my-admin && cd my-admin
# Initialize with CLI (installs everything!)
npx @hero-dynamic-form/client initThat's it! The CLI will:
- Create all project files
- Install all dependencies
- Setup TypeORM + PostgreSQL
- Configure @hero-dynamic-form/core
- Ready to run!
What Gets Created
my-admin/
├── src/
│ ├── backend/
│ │ └── index.ts # DynamicFormCore configuration
│ ├── datasource/
│ │ ├── index.ts # TypeORM DataSource
│ │ └── entity/
│ │ └── User.ts # Example User entity
│ └── frontend/
│ ├── index.html
│ ├── index.tsx
│ └── styles.css
├── webpack.dev.cjs
├── webpack.prod.cjs
├── tailwind.config.js
├── postcss.config.js
├── tsconfig.json
├── .babelrc
├── .env # Database config
├── .gitignore
└── package.jsonRun Your Project
# 1. Create database
createdb hero_admin_db
# 2. Update .env with your database credentials
# 3. Start development
npm run devOpen in browser:
- Frontend: http://localhost:3000
- Backend API: http://localhost:4000
- Health check: http://localhost:4000/health
- Schema: http://localhost:4000/schema
Auto-Generated CRUD API
Every entity you add automatically gets a full REST API:
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /api/user | List all users |
| GET | /api/user/:id | Get user by ID |
| POST | /api/user | Create new user |
| PUT | /api/user/:id | Update user |
| DELETE | /api/user/:id | Delete user |
Adding More Entities
1. Create a new entity:
// src/datasource/entity/Product.ts
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({ name: "products" })
export class Product {
@PrimaryGeneratedColumn()
id!: number;
@Column({ type: "varchar", length: 255 })
name!: string;
@Column({ type: "decimal", precision: 10, scale: 2 })
price!: number;
@Column({ type: "int", default: 0 })
stock!: number;
}2. Add to datasource:
// src/datasource/index.ts
import { Product } from "./entity/Product";
export const datasource = new DataSource({
// ...
entities: [User, Product], // Add here
});3. Register resource:
// src/backend/index.ts
import { Product } from "../datasource/entity/Product";
const config: DynamicFormCoreConfig = {
// ...
resources: [
{ name: "user", entity: User },
{ name: "product", entity: Product }, // Add here
],
};4. Restart server - New endpoints available:
GET /api/productPOST /api/product- etc.
Generated Backend Code
The CLI generates a complete DynamicFormCore setup:
// src/backend/index.ts
import "reflect-metadata";
import { datasource } from "../datasource";
import { User } from "../datasource/entity/User";
import { DynamicFormCore, DynamicFormCoreConfig } from "@hero-dynamic-form/core";
import { TypeORMEntityInspector } from "@hero-dynamic-form/typeorm-inspector";
const PORT = Number(process.env.PORT) || 4000;
const main = async () => {
await datasource.initialize();
console.log("Database connected");
const config: DynamicFormCoreConfig = {
dataSource: datasource as any,
entityInspector: new TypeORMEntityInspector(),
resources: [
{ name: "user", entity: User },
],
backend: { port: PORT },
cors: {
origin: ["http://localhost:3000"],
credentials: true,
},
};
const app = new DynamicFormCore(config);
await app.init();
app.start();
};
main().catch(console.error);Installed Dependencies
The CLI installs everything you need:
Runtime:
@hero-dynamic-form/core- Core framework@hero-dynamic-form/client- React components@hero-dynamic-form/typeorm-inspector- TypeORM adaptertypeorm- ORMpg- PostgreSQL driverreflect-metadata- Required for TypeORMreact,react-dom- Frontend
Development:
typescript,ts-node- TypeScriptwebpack,webpack-dev-server- Frontend bundlingtailwindcss,postcss- CSSnodemon- Auto-restartconcurrently- Run multiple scripts
npm Scripts
{
"dev": "concurrently \"npm run dev:frontend\" \"npm run dev:backend\"",
"dev:frontend": "webpack serve --config webpack.dev.cjs",
"dev:backend": "dotenv -e .env -- nodemon ...",
"build": "npm run build:frontend && npm run build:backend",
"start:backend": "node dist/backend/index.js"
}Development
# Install dependencies
pnpm install
# Build the package
pnpm run build
# Watch mode for development
pnpm run devPackage Exports
This package exports:
{
".": "./dist/index.js", // Components (Button, Card, etc.)
"./tailwind-preset": "./tailwind.preset.js" // Tailwind preset
}Files Included
dist/- Compiled JavaScript (ESM + CJS) with TypeScript definitionssrc/- Source code (for debugging & Tailwind scanning)tailwind.preset.js- Tailwind preset (recommended for consumers)postcss.config.mjs- PostCSS configurationbin/runner.cjs- CLI tool for project initialization
Requirements
- React >= 18.0.0
- Consumer project must have Tailwind CSS configured
License
MIT
