# tp-react-elements

A comprehensive React form library built with Material-UI and React Hook Form, designed for enterprise applications.

## 🆕 What's New

> Quick-glance log of notable fixes and changes. Newest entries first.
> Each entry should also be reflected in the affected component's
> Storybook docs (`*.stories.tsx` → `meta.parameters.docs.description`)
> so consumers see the same explanation in both places.

- **`SingleSelectSearchApi`** — The selected-value `Tooltip` is now suppressed
  via `open={false}` (controlled-closed) instead of relying on the Popper
  modifier fix. Background: the tooltip previously rendered pinned to the
  viewport's top-left corner (0,0) instead of near the input when the field
  sat inside an `overflow: hidden` ancestor (e.g. a table cell in
  `material-react-table` / `GenericPaginatedGrid`). Disabling Popper's `hide`
  modifier and using `rootBoundary: 'viewport'` **verifiably fixed this in
  Storybook (MUI v7)**, but the same build still mis-anchored when consumed
  live in apps pinned to MUI v6 (below our `@mui/material >=7.3.1` peer
  requirement) — MUI v6's Popper/Tooltip runtime ignores the modifier
  configuration. Rather than ship a tooltip that only behaves correctly on
  some MUI majors, we now suppress it at the prop level: `open={false}` forces
  MUI's `Tooltip` into fully-controlled mode so it never opens. The `Tooltip`
  element (and its modifier config) is **retained** (not removed) — flipping
  `open` back to the default is a one-line change once the anchoring fix is
  confirmed across all supported MUI majors. See the
  **"Tooltip inside a clipped container"** story in
  `SingleSelectSearchApi.stories.tsx` and the component's JSDoc for details.

## 🚀 Features

- **🔄 Seamless Integration** - Built on React Hook Form for performance and flexibility
- **🎨 Material Design** - Consistent with Material-UI design system
- **✅ Robust Validation** - Integrated with Yup for schema validation
- **♿ Accessibility First** - WCAG compliant with proper ARIA attributes
- **📝 TypeScript Ready** - Full type safety and IntelliSense support
- **📚 Rich Documentation** - Comprehensive docs with Storybook
- **🧪 Well Tested** - Extensive test coverage with React Testing Library

## 📋 Requirements

- **Node.js**: v18.17+ or v20.11+ (LTS recommended)
- **React**: v18.x or v19.x
- **TypeScript**: v5.x (recommended)

## 🔗 Supported Versions

| Package           | Supported Versions |
| ----------------- | ------------------ |
| React             | >=18 <20           |
| React DOM         | >=18 <20           |
| React Hook Form   | 7.x                |
| Material-UI       | 7.x                |
| Material-UI Icons | 7.x                |
| Emotion React     | 11.14.x            |
| Emotion Styled    | 11.14.x            |

## 📦 Installation

This library uses **peer dependencies** to avoid version conflicts and reduce bundle size. You need to install the required dependencies separately.

### 🚀 Quick Install (Recommended)

Install the library, then install only the core peer dependencies. Optional features (Rich Text, Session Timeout) can be added separately.

```bash
npm install tp-react-elements
# installs only core peers (no rich text, no idle timer)
npx install-tp-form-deps

# if you need Rich Text Editor
npx install-tp-form-deps --with-richtext

# or install optional peers manually
npm install jodit@^4.6.2 jodit-react@^5.2.19
```

## 🔍 Optimized Imports

To reduce bundle size, you can import only the components you need using subpath imports:

```js
// Import a specific component (top-level component folders only)
import { ModalField } from 'tp-react-elements/components/ModalField';

// Import Form module shortcuts
import { RenderForm } from 'tp-react-elements/form';

// Import utilities
import * as Utils from 'tp-react-elements/utils';
```

See our [Subpath Imports Guide](./docs/subpath-imports.md) for detailed instructions on optimizing your imports.

### 📋 Manual Installation

#### Step 1: Install Required Dependencies (Core)

```bash
npm install react@^19.1.1 react-dom@^19.1.1 \
  react-hook-form@^7.62.0 \
  @mui/material@^7.3.1 @mui/icons-material@^7.3.1 \
  @emotion/react@^11.14.0 @emotion/styled@^11.14.1 \
  @mui/x-date-pickers@^8.10.2 \
  @hookform/error-message@^2.0.1 @hookform/resolvers@^5.2.1 \
  date-fns@^4.1.0 dayjs@^1.11.13 \
  yup@^1.7.0 \
  crypto-js@^4.2.0 file-saver@^2.0.5 xlsx-js-style@^1.2.0
```

#### Step 2: Optional Dependencies

```bash
# Rich Text Editor (optional)
npm install jodit@^4.6.2 jodit-react@^5.2.19

# Session timeout (optional)
npm install react-idle-timer@^5.7.2
```

#### Step 3: Install the Library

```bash
npm install tp-react-elements
```

## 🎯 Quick Start

```tsx
import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { Input } from "tp-react-elements";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";

const schema = yup.object({
  email: yup.string().email().required(),
  password: yup.string().min(8).required(),
});

function LoginForm() {
  const { control, handleSubmit } = useForm({
    resolver: yupResolver(schema),
  });

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <ThemeProvider theme={createTheme()}>
      <CssBaseline />
      <form onSubmit={handleSubmit(onSubmit)}>
        <Input
          name="email"
          control={control}
          label="Email Address"
          type="email"
          required
          fullWidth
        />
        <Input
          name="password"
          control={control}
          label="Password"
          type="password"
          required
          fullWidth
        />
        <button type="submit">Sign In</button>
      </form>
    </ThemeProvider>
  );
}
```

## 📋 Components

The library provides a comprehensive set of form components that integrate seamlessly with React Hook Form and Material-UI:

- **Input** - Text input fields with various types (text, email, password, etc.)
- **Select** - Single and multi-select dropdowns with autocomplete
- **DatePicker** - Calendar-based date selection
- **TimePicker** - Time selection with various formats
- **FileUpload** - File upload with preview and validation
- **RichTextEditor** - WYSIWYG editor for formatted text
- **Checkbox** - Single and group checkbox components
- **RadioGroup** - Radio button selection groups
- **Switch** - Toggle switches for boolean values
- **Form** - Container component with built-in validation
- **GenericPaginatedGrid** - Server-paginated data grid with dynamic filter chips (see Storybook **Docs → Paginated Grid**)

Refer to our Storybook documentation for detailed API documentation and examples.

### Paginated grid (Storybook)

```bash
npm run storybook
```

- **Docs → Paginated Grid** — API reference plus **four copy-paste examples** (embedded panel, wrapped headers, typography, invoice filters)
- **Components → PaginatedGrid → Sample Grids** — mock grids (no API): header wrap, compact layout, viewport fill, multi-select with Apply button, month picker
- **Components → PaginatedGrid → Example Grid** — invoice grid demo using mock data (no API)

**Global Search:** every `GenericPaginatedGrid` includes a built-in search icon in the top-right toolbar — **collapsed by default** (set `showGlobalSearchByDefault={true}` to start expanded). Click the icon to expand a free-text search that filters across all visible columns of the current batch. See **Docs → Paginated Grid → Global search**.

**Excel export:** the Export button downloads an `.xlsx` file with the header row styled in `headerBgColor` (bold white text) and columns auto-sized to fit content. Requires `xlsx-js-style` as a peer dependency.

**Element IDs:** every interactive element (toolbar buttons, filter chips, pagination controls) receives a stable `id` attribute. Pass `gridId="invoice"` (or omit to default to `exportFilename`) and all elements follow the pattern `{gridId}_refresh_icon`, `{gridId}_dateRange_chip`, `{gridId}_next_page_icon`, etc. See **Docs → Paginated Grid — Element IDs** in Storybook for the full reference table.

**Example — compact embedded grid with smaller fonts:**

```tsx
<GenericPaginatedGrid
  tableHeight="calc(100vh - 240px)"
  autoFillViewport={false}
  uiDensity="compact"
  headerBgColor="#f5f5f5"
  headerMaxHeight={64}
  headerFontSize={11}
  bodyFontSize={10}
  {...gridProps}
/>
```

**Example — wrapped header “Department / Business Unit”:**

```tsx
<GenericPaginatedGrid
  headerBgColor="#e8eaf6"
  headerMinHeight="48px"
  headerMaxHeight="96px"
  headerFontSize={12}
  bodyFontSize={12}
  layoutMode="grid"
  {...gridProps}
/>
```

Full examples: Storybook **Docs → Paginated Grid → Examples**.

## 🏗️ Best Practices for Code Structure and Organization

### Component Organization

- **Feature-Based Organization**: Group related components together in feature-based directories for better organization.

  ```
  src/
    features/
      text-inputs/
      date-pickers/
      selects/
      file-uploads/
  ```

- **Component Documentation**: Add JSDoc comments to all components and functions, describing their purpose, props, and usage examples.

- **Component Factories**: Implement factory patterns for similar components to reduce code duplication.

  ```typescript
  // Example of a component factory
  const createFormField = (FieldComponent) => {
    return ({ name, control, label, ...props }) => (
      <Controller
        name={name}
        control={control}
        render={({ field, fieldState }) => (
          <FieldComponent
            {...field}
            label={label}
            error={!!fieldState.error}
            helperText={fieldState.error?.message}
            {...props}
          />
        )}
      />
    );
  };
  ```

- **Barrel Exports**: Use barrel files (index.ts) to simplify imports for consumers.

- **Naming Conventions**: Adopt consistent naming conventions across the codebase (PascalCase for components, camelCase for utilities).

## ⚡ Performance Optimization

- **Component Memoization**: Use React.memo for complex components to prevent unnecessary re-renders.

  ```typescript
  const MemoizedFormField = React.memo(FormField, (prevProps, nextProps) => {
    return prevProps.value === nextProps.value && prevProps.error === nextProps.error;
  });
  ```

- **Code Splitting**: Implement dynamic imports for larger components to reduce initial load time.

  ```typescript
  // Use dynamic imports for complex components
  const RichTextEditor = React.lazy(() => import('./RichTextEditor'));
  ```

- **Tree-Shaking Friendly Exports**: Ensure all exports are compatible with tree-shaking.

- **Debounced Validation**: Implement debounced validation for fields with expensive validation operations.

  ```typescript
  const debouncedValidate = useCallback(
    debounce((value) => validateField(value), 300),
    []
  );
  ```

- **Virtual Rendering**: For components that render large lists, implement virtualization to improve performance.

- **Context Optimization**: Split context providers to minimize re-renders when state changes.

  ```typescript
  // Split form context into smaller, focused contexts
  const FormValuesContext = createContext({});
  const FormErrorsContext = createContext({});
  ```

## 📚 Documentation and Usability

- **Interactive Examples**: Enhance Storybook documentation with interactive examples for common use cases.

- **Component Playground**: Create an online playground for experimenting with components in real-time.

- **Migration Guides**: Provide comprehensive migration guides for major version updates.

- **Enhanced Type Definitions**: Improve TypeScript definitions with descriptive comments and examples.

  ```typescript
  /**
   * Props for the Input component
   * @example
   * <Input
   *   name="email"
   *   control={control}
   *   label="Email Address"
   *   required
   * />
   */
  export interface InputProps {
    /** Field name in the form */
    name: string;
    /** Form control from useForm hook */
    control: Control<any>;
    // ... other props
  }
  ```

- **Theme Customization Guide**: Document how to customize the theme to match brand guidelines.

- **Accessibility Documentation**: Add specific documentation about accessibility features and how to maintain accessibility when customizing components.

- **Performance Best Practices**: Document performance considerations for using the library in large applications.

## 🔧 For Library Developers

If you're contributing to this library or setting up for development:

### Development Setup

```bash
# Clone the repository
git clone https://github.com/your-office/form-elements.git
cd form-elements

# Install all dependencies (including devDependencies)
npm install

# Start development server
npm run dev

# Run tests
npm test

# Build the library
npm run build
```

### Dependency Structure

- **`peerDependencies`**: Required by library consumers, must be installed separately
- **`devDependencies`**: Required for development, testing, and building the library
- **`dependencies`**: Empty (following library best practices)

### Why Peer Dependencies?

1. **Avoid Version Conflicts**: Prevents multiple versions of React, MUI, etc.
2. **Smaller Bundle Size**: No duplicate packages in consumer projects
3. **Version Control**: Users control which versions they use
4. **Industry Standard**: Same pattern used by MUI, React Hook Form, etc.

### Reducing “Wide” Peer Dependencies

- Make non-core peers optional: Rich text (`jodit`, `jodit-react`) and session timeout (`react-idle-timer`) are optional and not installed by default via `install-tp-form-deps`.
- Feature subpackages (advanced): Move heavy features into dedicated entry points (e.g., `tp-react-elements/richtext`) with their own peer sets.
- Thin wrappers (advanced): Provide adapters that lazy-load optional features so apps that don’t use them never import those packages.
- Clear installer flags: Use `--with-richtext` and `--with-idle` (or `--all`) to explicitly include optional peers only when needed.

## 📝 License

MIT
