npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@hero-dynamic-form/client

v1.0.51

Published

React components library for Hero Dynamic Forms with Tailwind CSS support.

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/client

Setup

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/forms and @tailwindcss/typography included
  • 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:

  1. Components are NOT pre-compiled - They export React components with Tailwind classes like bg-primary-600, text-white, etc.

  2. Consumer's Tailwind scans the package - Via the content configuration, Tailwind will scan node_modules/@hero-dynamic-form/client/**/*.{js,tsx} to find all Tailwind classes used.

  3. 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/client components
    • 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 variant
  • size?: 'sm' | 'md' | 'lg' - Button size
  • children: 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 title
  • children: React.ReactNode - Card content
  • className?: 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 < runtime

Built-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 init

That'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.json

Run Your Project

# 1. Create database
createdb hero_admin_db

# 2. Update .env with your database credentials

# 3. Start development
npm run dev

Open 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/product
  • POST /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 adapter
  • typeorm - ORM
  • pg - PostgreSQL driver
  • reflect-metadata - Required for TypeORM
  • react, react-dom - Frontend

Development:

  • typescript, ts-node - TypeScript
  • webpack, webpack-dev-server - Frontend bundling
  • tailwindcss, postcss - CSS
  • nodemon - Auto-restart
  • concurrently - 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 dev

Package 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 definitions
  • src/ - Source code (for debugging & Tailwind scanning)
  • tailwind.preset.js - Tailwind preset (recommended for consumers)
  • postcss.config.mjs - PostCSS configuration
  • bin/runner.cjs - CLI tool for project initialization

Requirements

  • React >= 18.0.0
  • Consumer project must have Tailwind CSS configured

License

MIT