{"id":31513928,"url":"https://github.com/liangk/lite-form","last_synced_at":"2025-10-03T02:03:45.179Z","repository":{"id":306723857,"uuid":"1026562099","full_name":"liangk/lite-form","owner":"liangk","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-01T01:11:23.000Z","size":440,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-01T01:22:46.668Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/liangk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-26T06:15:37.000Z","updated_at":"2025-10-01T01:11:27.000Z","dependencies_parsed_at":"2025-07-27T08:40:29.661Z","dependency_job_id":"53b3129d-bbe6-4b28-a1ee-1e823d7f6067","html_url":"https://github.com/liangk/lite-form","commit_stats":null,"previous_names":["liangk/lite-form"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/liangk/lite-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liangk%2Flite-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liangk%2Flite-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liangk%2Flite-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liangk%2Flite-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liangk","download_url":"https://codeload.github.com/liangk/lite-form/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liangk%2Flite-form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278100044,"owners_count":25929782,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-03T02:00:06.070Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-03T02:01:02.514Z","updated_at":"2025-10-03T02:03:45.160Z","avatar_url":"https://github.com/liangk.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Forms"],"readme":"# Lite Form: A Lightweight and Powerful Angular Form Library\n\n**Lite Form is a comprehensive, open-source library of 13+ standalone components for building modern, reactive forms in Angular (v20+). It provides lightweight, customizable, and fully-typed form controls—from basic inputs to advanced data tables and loading indicators—designed to accelerate development and improve user experience.**\n\nThis library is built for developers who need a robust, out-of-the-box solution for form-heavy applications without the overhead of heavy-weight dependencies. All components are standalone, tree-shakable, and integrate seamlessly with Angular's Reactive Forms module.\n\n## Why Choose Lite Form?\n\n- **Accelerate Development**: Get a complete suite of form controls ready to use, including complex components like date pickers, file uploads, and data tables. Drastically reduce boilerplate code.\n- **Lightweight \u0026 Performant**: Built with modern Angular practices. All components are standalone and tree-shakable, ensuring a minimal bundle size.\n- **Fully Typed \u0026 Integrated**: Enjoy excellent developer experience with fully-typed APIs for all components and Data Transfer Objects (DTOs), ensuring type safety and easier integration.\n- **Highly Customizable**: While providing a clean default UI, the library is designed for easy styling. A clear SCSS structure and BEM-style classes allow for deep customization to match your brand.\n- **Secure \u0026 Accessible**: Components are built with security and accessibility (ARIA) in mind, including advanced password strength analysis and accessible form field structures.\n\n## Live Demo\n\nExperience Lite Form in action with our interactive live demo on StackBlitz. Test out all the components and see how they work in a real Angular application.\n\n[**Launch Live Demo on StackBlitz**](https://stackblitz.com/~/github.com/liangk/lite-form)\n\n\n## Use Cases\n\nLite Form is ideal for a wide range of applications, including but not limited to:\n\n- **Enterprise Applications**: Build complex forms for data entry, configuration, and management with robust validation.\n- **Dashboards and Admin Panels**: Quickly create settings pages, user management forms, and data tables.\n- **Customer-Facing Websites**: Implement user-friendly registration, login, and profile forms.\n- **E-commerce**: Develop streamlined checkout processes and product configuration forms.\n- **Internal Tools**: Rapidly prototype and build internal tools for data collection and management.\n\n## Features\n- **Modern Angular 20+** - Built with standalone components, signals, and latest CLI tooling\n- **TypeScript Support** - Fully typed with generic support and DTO helpers\n- **Reactive Forms** - Integrated with Angular Reactive Forms\n- **Built-in Validation** - Form validation with error messages and utilities\n- **Password Security** - Advanced password validation and strength analysis\n- **Date Handling** - Single date and date range selection with custom formatting\n- **File Upload** - Drag \u0026 drop file upload with camera capture and file management\n- **Panels \u0026 Dialogs** - Modal panels supporting string, template, or component content with configurable action buttons\n- **Data Tables** - Flexible table component with custom columns, sorting, and pagination\n- **Pagination** - Standalone pagination component with customizable navigation\n- **Loading Indicators** - Spinner and progress bar components with defined/indeterminate states\n- **Customizable Styling** - Space-saving SCSS style guide for consistent overrides\n- **Accessibility** - ARIA-compliant form controls\n- **Animations** - Smooth transitions and interactions\n\n## Components\n\n### LiteInput\nBasic text input component with floating labels and validation.\n\n### LitePassword\nPassword input component with toggle visibility, strength indicator, and advanced validation features.\n\n### LiteTextarea  \nMulti-line text input with auto-resize capabilities.\n\n### LiteSelect\nSingle-selection dropdown with search and filtering.\n\n### LiteMultiSelect\nMulti-selection dropdown with inline selected items display and dynamic height adjustment.\n\n### LiteRadio\nRadio button group component for single selection from multiple options.\n\n### LiteCheckbox\nCheckbox component for boolean input with validation support.\n\n### LiteDate\nAdvanced date picker component with single date and date range selection, custom formatting, and intelligent calendar positioning.\n\n### LiteFile\nFile upload component with drag \u0026 drop, badge, file management panel, and camera capture support.\n\n### LiteDateTime\nDate and time picker with timezone-safe handling and consistent formatting utilities.\n\n### LiteTable\nFlexible data table component with custom columns, cell templates, nested property access, and integrated pagination.\n\n### LitePaginator\nStandalone pagination component with customizable page navigation, items per page selection, and total item display.\n\n### LitePanel\nModal-style panel component that renders string content, Angular templates, or dynamic components. Supports configurable header text and action buttons via `LitePanelAction` definitions. Accepts custom `width`, `height`, `maxWidth`, and `maxHeight` inputs with automatic `px` suffix for numeric values.\n\n### LiteLoading\nLoading indicator component with view toggle for spinner (loading wheel) or progress bar modes. Supports defined progress percentage (0-100) or indeterminate animation, optional message display, and configurable spinner sizes (small, medium, large).\n\n---\n\n## Installation\n\n```bash\nnpm install ngx-lite-form\n```\n\n## Quick Start\n\n### 1. Import Components\n\n```typescript\nimport {\n  LiteInput,\n  LitePassword,\n  LiteTextarea,\n  LiteSelect,\n  LiteMultiSelect,\n  LiteRadio,\n  LiteCheckbox,\n  LiteDate,\n  LiteDateTime,\n  LiteFile,\n  LiteTable,\n  LitePaginator,\n  LitePanel,\n  LiteLoading\n} from 'ngx-lite-form';\nimport { FormControl, Validators } from '@angular/forms';\n\nimport {\n  FieldDto,\n  SelectFieldDto,\n  MultiSelectFieldDto,\n  RadioFieldDto,\n  DateRangeFieldDto,\n  FileFieldDto,\n  TableFieldDto,\n  PaginatorFieldDto,\n  LitePanelAction\n} from 'ngx-lite-form';\n\n@Component({\n  standalone: true,\n  imports: [\n    LiteInput,\n    LitePassword,\n    LiteTextarea,\n    LiteSelect,\n    LiteMultiSelect,\n    LiteRadio,\n    LiteCheckbox,\n    LiteDate,\n    LiteDateTime,\n    LiteFile,\n    LiteTable,\n    LitePaginator,\n    LiteLoading\n  ],\n  templateUrl: './app.component.html',\n  styleUrl: './app.component.scss'\n})\nexport class AppComponent {\n  // Basic input\n  nameField = new FieldDto('Full Name', new FormControl(''));\n  \n  // Number input\n  ageField = new FieldDto('Age', new FormControl(0), 2, 'number');\n  \n  // Password with validation\n  passwordField = new FieldDto('Password', new FormControl('', [\n    Validators.required,\n    Validators.minLength(8),\n    Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?\u0026])[A-Za-z\\d@$!%*?\u0026]{8,}$/)\n  ]));\n  \n  // Textarea\n  descriptionField = new FieldDto('Description', new FormControl(''), 4);\n  \n  // Checkbox (using basic FieldDto for boolean)\n  agreeField = new FieldDto('I agree to terms', new FormControl\u003cboolean\u003e(false, { nonNullable: true }));\n  \n  // Select dropdown\n  countryField = new SelectFieldDto(\n    'Country',\n    new FormControl(''),\n    ['USA', 'Canada', 'Mexico'],\n    (option) =\u003e option\n  );\n  \n  // Multi-select\n  skillsField = new MultiSelectFieldDto(\n    'Skills',\n    new FormControl\u003cstring[]\u003e([]),\n    ['JavaScript', 'TypeScript', 'Angular', 'React'],\n    (option) =\u003e option\n  );\n  \n  // Radio group\n  planField = new RadioFieldDto(\n    'Choose Plan',\n    new FormControl(''),\n    ['Basic', 'Premium', 'Enterprise'],\n    (option) =\u003e option\n  );\n  \n  // Single date\n  birthdateField: FieldDto = {\n    label: 'Birth Date',\n    formControl: new FormControl\u003cstring\u003e('', { nonNullable: true })\n  };\n  \n  // Date range\n  eventDateField: DateRangeFieldDto = {\n    label: 'Event Date Range',\n    formControl: new FormControl\u003cstring[]\u003e(['', ''], { nonNullable: true })\n  };\n  \n  // File upload\n  fileField = new FileFieldDto('Attachments', new FormControl([]), {\n    multiple: true,\n    accept: 'image/*,application/pdf',\n    maxFileSize: 5 * 1024 * 1024,\n    maxFiles: 5,\n    showPreview: true\n  });\n\n  // Table with custom columns\n  employeeTable = new TableFieldDto(\n    [\n      { key: 'name', label: 'Name', flex: '1' },\n      { key: 'department', label: 'Department', flex: '0 0 150px' },\n      { key: 'salary', label: 'Salary', flex: '0 0 120px', cellTemplate: (value) =\u003e `$${value?.toLocaleString() || '0'}` }\n    ],\n    [\n      { name: 'John Smith', department: 'Engineering', salary: 75000 },\n      { name: 'Sarah Johnson', department: 'Marketing', salary: 65000 }\n    ]\n  );\n\n  // Paginated table\n  userTable = new TableFieldDto(\n    [\n      { key: 'name', label: 'Name', flex: '1' },\n      { key: 'email', label: 'Email', flex: '1' },\n      { key: 'location.country', label: 'Country', flex: '0 0 120px' }\n    ],\n    [], // Will be populated by API\n    true, // Enable pagination\n    new PaginatorFieldDto(1, 100, 10) // Page 1, 100 total items, 10 per page\n  );\n\n  // Standalone paginator\n  paginator = new PaginatorFieldDto(1, 500, 25);\n\n  // Panel demo state\n  basicPanelOpen = signal(false);\n  panelResult = signal\u003cunknown | null\u003e(null);\n  confirmationActions: LitePanelAction[] = [\n    { label: 'Confirm', value: 'confirm', variant: 'danger' },\n    { label: 'Cancel', value: null, variant: 'secondary' }\n  ];\n\n  openPanel() {\n    this.panelResult.set(null);\n    this.basicPanelOpen.set(true);\n  }\n\n  onPanelClosed(result: unknown | null) {\n    this.panelResult.set(result);\n    this.basicPanelOpen.set(false);\n  }\n}\n```\n\n### 3. Use in Templates\n\n```html\n\u003cform\u003e\n  \u003clite-input [control]=\"nameField\"\u003e\u003c/lite-input\u003e\n  \u003clite-password [control]=\"passwordField\" [showStrengthIndicator]=\"true\"\u003e\u003c/lite-password\u003e\n  \u003clite-textarea [control]=\"descriptionField\"\u003e\u003c/lite-textarea\u003e\n  \u003clite-checkbox [control]=\"agreeField\"\u003e\u003c/lite-checkbox\u003e\n  \u003clite-select [control]=\"countryField\"\u003e\u003c/lite-select\u003e\n  \u003clite-multi-select [control]=\"skillsField\"\u003e\u003c/lite-multi-select\u003e\n  \u003clite-radio [control]=\"planField\"\u003e\u003c/lite-radio\u003e\n  \u003clite-date [control]=\"birthdateField\"\u003e\u003c/lite-date\u003e\n  \u003clite-date [control]=\"eventDateField\" [range]=\"true\" [format]=\"'dd/MM/yyyy'\"\u003e\u003c/lite-date\u003e\n  \u003clite-file [control]=\"fileField\"\u003e\u003c/lite-file\u003e\n\u003c/form\u003e\n\n\u003c!-- Data Table --\u003e\n\u003clite-table [table]=\"employeeTable\"\u003e\u003c/lite-table\u003e\n\n\u003c!-- Paginated Table --\u003e\n\u003clite-table\n  [table]=\"userTable\"\n  (pageChange)=\"onPageChange($event)\"\n  (itemsPerPageChange)=\"onItemsPerPageChange($event)\"\u003e\n\u003c/lite-table\u003e\n\n\u003c!-- Standalone Paginator --\u003e\n\u003clite-paginator\n  [paginator]=\"paginator\"\n  (pageChange)=\"onPaginatorPageChange($event)\"\n  (itemsPerPageChange)=\"onPaginatorItemsChange($event)\"\u003e\n\u003c/lite-paginator\u003e\n\n\u003c!-- Lite Panel --\u003e\n\u003cbutton type=\"button\" (click)=\"openPanel()\"\u003eOpen Panel\u003c/button\u003e\n\n@if (basicPanelOpen()) {\n  \u003clite-panel\n    [title]=\"'Review details'\"\n    [content]=\"panelTemplate\"\n    [actions]=\"confirmationActions\"\n    (closed)=\"onPanelClosed($event)\"\u003e\n  \u003c/lite-panel\u003e\n}\n\n\u003cng-template #panelTemplate let-close=\"close\"\u003e\n  \u003cp\u003ePanel content can render any Angular template.\u003c/p\u003e\n  \u003cbutton type=\"button\" (click)=\"close('acknowledged')\"\u003eAcknowledge\u003c/button\u003e\n\u003c/ng-template\u003e\n\n\u003c!-- Loading Indicators --\u003e\n\u003c!-- Spinner (default) --\u003e\n\u003clite-loading [message]=\"'Loading data...'\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Spinner with size --\u003e\n\u003clite-loading [size]=\"'large'\" [message]=\"'Processing...'\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Progress bar with defined percentage --\u003e\n\u003clite-loading \n  [view]=\"'progress'\" \n  [progress]=\"75\" \n  [message]=\"'Uploading files...'\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Indeterminate progress bar --\u003e\n\u003clite-loading \n  [view]=\"'progress'\" \n  [message]=\"'Processing your request...'\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Controlled visibility --\u003e\n\u003clite-loading [visible]=\"isLoading\" [message]=\"'Please wait...'\"\u003e\u003c/lite-loading\u003e\n```\n---\n\n## Component Documentation\n\n### LiteInput Component\n\n**Selector:** `lite-input`\n\n| Input    | Type        | Default | Description                               |\n| :------- | :---------- | :------ | :---------------------------------------- |\n| `control`| `FieldDto`  | -       | Field configuration and form control.     |\n| `inEdit` | `boolean`   | `true`  | Toggles between edit and read-only mode. |\n\n**Example:**\n```typescript\n// Component\nnameField = new FieldDto('Full Name', new FormControl('', [Validators.required]));\n\n// Template\n\u003clite-input [control]=\"nameField\"\u003e\u003c/lite-input\u003e\n```\n\n### LitePassword Component\n\n**Selector:** `lite-password`\n\n| Input                   | Type      | Default | Description                                            |\n| :---------------------- | :-------- | :------ | :----------------------------------------------------- |\n| `control`               | `FieldDto`| -       | Field configuration and form control.                  |\n| `inEdit`                | `boolean` | `true`  | Toggles between edit and read-only mode.               |\n| `showToggle`            | `boolean` | `true`  | If `true`, shows the password visibility toggle button.  |\n| `showStrengthIndicator` | `boolean` | `false` | If `true`, shows the password strength analysis bar.   |\n\n**Features:**\n- Password visibility toggle with eye/eye-off icons\n- Real-time password strength analysis\n- Advanced password validation error messages\n- Support for complex password patterns\n- Accessibility features (ARIA labels)\n\n**Example:**\n```typescript\n// Basic password\npasswordField = new FieldDto('Password', new FormControl('', [\n  Validators.required,\n  Validators.minLength(8)\n]));\n\n// Advanced password with pattern validation\nstrongPasswordField = new FieldDto('Strong Password', new FormControl('', [\n  Validators.required,\n  Validators.minLength(8),\n  Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?\u0026])[A-Za-z\\d@$!%*?\u0026]{8,}$/)\n]));\n\n// Template\n\u003clite-password [control]=\"passwordField\"\u003e\u003c/lite-password\u003e\n\u003clite-password [control]=\"strongPasswordField\" [showStrengthIndicator]=\"true\"\u003e\u003c/lite-password\u003e\n\u003clite-password [control]=\"confirmPasswordField\" [showToggle]=\"false\"\u003e\u003c/lite-password\u003e\n```\n\n**Password Strength Analysis:**\n```typescript\nimport { FormUtils } from 'ngx-lite-form';\n\n// Analyze password strength programmatically\nconst analysis = FormUtils.analyzePasswordStrength('MyStr0ng@Pass');\n// Returns: { score: 6, level: 'Good', feedback: ['Consider using 12+ characters'] }\n```\n\n### LiteTextarea Component\n\n**Selector:** `lite-textarea`\n\n| Input     | Type       | Default | Description                                                   |\n| :-------- | :--------- | :------ | :------------------------------------------------------------ |\n| `control` | `FieldDto` | -       | Field configuration, including `rows` for initial height.     |\n| `inEdit`  | `boolean`  | `true`  | Toggles between edit and read-only mode.                      |\n\n**Example:**\n```typescript\n// Component\n// With validation\ndescriptionField = new FieldDto('Description', new FormControl(''), 4);\n\n// Template\n\u003clite-textarea [control]=\"descriptionField\"\u003e\u003c/lite-textarea\u003e\n```\n\n### LiteSelect Component\n\n**Selector:** `lite-select`\n\n| Input     | Type                | Default | Description                                      |\n| :-------- | :------------------ | :------ | :----------------------------------------------- |\n| `control` | `SelectFieldDto\u003cT\u003e` | -       | Field configuration, including `options`.        |\n| `inEdit`  | `boolean`           | `true`  | Toggles between edit and read-only mode.         |\n\n**Example:**\n```typescript\n// Component\nstatusField = new SelectFieldDto(\n  'Status',\n  new FormControl(''),\n  [\n    { id: 1, name: 'Active' },\n    { id: 2, name: 'Inactive' }\n  ],\n  (option) =\u003e option.name\n);\n\n// Template\n\u003clite-select [control]=\"statusField\"\u003e\u003c/lite-select\u003e\n```\n\n### LiteMultiSelect Component\n\n**Selector:** `lite-multi-select`\n\n| Input     | Type                     | Default | Description                                      |\n| :-------- | :----------------------- | :------ | :----------------------------------------------- |\n| `control` | `MultiSelectFieldDto\u003cT\u003e` | -       | Field configuration, including `options`.        |\n| `inEdit`  | `boolean`                | `true`  | Toggles between edit and read-only mode.         |\n\n**Features:**\n- Inline selected items display\n- Dynamic height adjustment\n- Filtering/search functionality\n- Individual item removal\n\n**Example:**\n```typescript\n// Component\ntagsField = new MultiSelectFieldDto(\n  'Tags',\n  new FormControl\u003cstring[]\u003e([]),\n  ['Frontend', 'Backend', 'DevOps', 'Testing'],\n  (option) =\u003e option\n);\n\n// Template\n\u003clite-multi-select [control]=\"tagsField\"\u003e\u003c/lite-multi-select\u003e\n```\n\n### LiteDate Component\n\n**Selector:** `lite-date`\n\n| Input     | Type                          | Default        | Description                                      |\n| :-------- | :---------------------------- | :------------- | :----------------------------------------------- |\n| `control` | `FieldDto` or `DateRangeFieldDto` | -              | Field configuration for single or range date.    |\n| `inEdit`  | `boolean`                     | `true`         | Toggles between edit and read-only mode.         |\n| `format`  | `string`                      | `'dd/MM/yyyy'` | Date display format string.                      |\n| `range`   | `boolean`                     | `false`        | If `true`, enables date range selection mode.    |\n\n**Features:**\n- Single date and date range selection\n- Custom date formatting (dd/MM/yyyy, MM/dd/yyyy, yyyy-MM-dd)\n- Intelligent calendar positioning (auto-adjusts based on screen space)\n- Dual calendar display for range selection\n- Visual range highlighting with different styles for start, end, and in-between dates\n- Manual input parsing with format validation\n- Timezone-safe date handling\n- Today's date highlighting with distinctive styling\n- Auto-close calendar after range selection\n\n**Single Date Example:**\n```typescript\n// Component\nbirthdateField: FieldDto = {\n  label: 'Birth Date',\n  formControl: new FormControl\u003cstring\u003e('', { \n    nonNullable: true, \n    validators: [Validators.required] \n  })\n};\n\n// Template\n\u003clite-date [control]=\"birthdateField\" [format]=\"'dd/MM/yyyy'\"\u003e\u003c/lite-date\u003e\n```\n\n**Date Range Example:**\n```typescript\n// Component\nimport { DateRangeFieldDto } from 'ngx-lite-form';\n\neventDateField: DateRangeFieldDto = {\n  label: 'Event Date Range',\n  formControl: new FormControl\u003cstring[]\u003e(['', ''], { nonNullable: true })\n};\n\n// Template\n\u003clite-date [control]=\"eventDateField\" [range]=\"true\" [format]=\"'dd/MM/yyyy'\"\u003e\u003c/lite-date\u003e\n```\n\n**Range Selection Behavior:**\n- First click: Sets start date, clears any existing range\n- Second click: Sets end date, completes range selection\n- Clicking same date twice: Resets to single start date\n- Auto-orders dates (earlier date becomes start, later becomes end)\n- Calendar auto-closes 1 second after completing range selection\n\n### LiteFile Component\n\n**Selector:** `lite-file`\n\n| Input     | Type           | Default | Description                                      |\n| :-------- | :------------- | :------ | :----------------------------------------------- |\n| `control` | `FileFieldDto` | -       | Field configuration for file uploads.            |\n| `inEdit`  | `boolean`      | `true`  | Toggles between edit and read-only mode.         |\n\n**Features:**\n- File upload via button, drag \u0026 drop, or camera capture (on supported devices)\n- Always-visible badge shows file count\n- Management panel lists files, upload area, and action buttons\n- Camera capture on devices with a camera using `\u003cinput type=\"file\" accept=\"image/*\" capture=\"environment\"\u003e`\n- Validation: max files, max file size, file type restrictions\n- Image preview with thumbnails for image files\n- Progress tracking for file uploads\n- Accessibility: keyboard and screen reader friendly\n\n**Example:**\n```typescript\n// Component\nimport { FileFieldDto } from 'ngx-lite-form';\n\n// Basic file upload\nfileField = new FileFieldDto('Upload Files', new FormControl([]));\n\n// Image upload with restrictions\nimageField = new FileFieldDto(\n  'Profile Picture',\n  new FormControl([]),\n  false, // single file only\n  'image/*', // images only\n  2 * 1024 * 1024, // 2MB limit\n  1, // max 1 file\n  true // show preview\n);\n\n// Template\n\u003clite-file [control]=\"fileField\"\u003e\u003c/lite-file\u003e\n\u003clite-file [control]=\"imageField\"\u003e\u003c/lite-file\u003e\n```\n\n**Camera Capture:**\n- The \"Take Picture\" button opens the device camera using a hidden file input with `accept=\"image/*\" capture=\"environment\"`\n- Works on mobile devices and laptops with a camera\n- On desktops without a camera, the button will do nothing or fall back to file selection\n- No special permissions required, but the browser may prompt for camera access\n\n**File Management Panel:**\n- Click the file icon button to open the management panel\n- Drag \u0026 drop files or click the upload area to select files\n- Use action buttons to upload files, take a picture, or close the panel\n- Remove files individually or clear all files\n\n### LiteTable Component\n\n**Selector:** `lite-table`\n\n| Input   | Type                | Default | Description                                      |\n| :------ | :------------------ | :------ | :----------------------------------------------- |\n| `table` | `TableFieldDto\u003cT\u003e`  | -       | Table configuration including columns and data.  |\n\n| Output               | Type                             | Description                                            |\n| :------------------- | :------------------------------- | :----------------------------------------------------- |\n| `pageChange`         | `number`                         | Emitted with the new page number on page change.       |\n| `itemsPerPageChange` | `number`                         | Emitted with the new items-per-page count.             |\n| `menuAction`         | `{ action: string; row: T }`     | Emitted when a row action is selected from a menu.     |\n\n**Features:**\n- Flexbox-based responsive layout for modern table design\n- Custom column definitions with labels, flex sizing, and cell templates\n- Support for nested object property access (dot notation)\n- Integrated pagination with lite-paginator component\n- Custom cell templates for advanced formatting (images, status indicators, dates)\n- Automatic handling of special data formats (name objects, nested properties)\n- Empty state display when no data is available\n- Sorting indicators (visual styling support)\n- Per-row actions menu via a dedicated `menu`-type column (kebab/tri-dot)\n\n**Example:**\n```typescript\n// Component\nimport { TableFieldDto, TableColumn } from 'ngx-lite-form';\n\ninterface Product {\n  id: number;\n  name: string;\n  price: number;\n  category: string;\n  inStock: boolean;\n}\n\nconst columns: TableColumn[] = [\n  { key: 'id', label: 'ID', flex: '0 0 80px' },\n  { key: 'name', label: 'Product Name', flex: '2' },\n  { key: 'price', label: 'Price', flex: '0 0 100px', cellTemplate: (value) =\u003e `$${value?.toFixed(2)}` },\n  { key: 'category', label: 'Category', flex: '1' },\n  { key: 'inStock', label: 'Status', flex: '0 0 100px', cellTemplate: (value) =\u003e value ? '✓ In Stock' : '✗ Out of Stock' }\n];\n\nproductTable = new TableFieldDto(columns, productData, false);\n\n// Template\n\u003clite-table [table]=\"productTable\"\u003e\u003c/lite-table\u003e\n```\n\n#### Row Actions Menu\n\nAdd a dedicated menu column to show a kebab (tri-dot) button per row. Configure menu items on the column and handle the `(menuAction)` output.\n\n```typescript\nimport { TableFieldDto, TableColumn } from 'ngx-lite-form';\n\nconst columns: TableColumn[] = [\n  { key: 'name', label: 'Name', flex: '1' },\n  { key: 'email', label: 'Email', flex: '1' },\n  // Menu column (last column)\n  {\n    key: 'actions',\n    label: '',\n    flex: '0 0 44px',\n    type: 'menu',\n    menuItems: [\n      { label: 'Edit', value: 'edit' },\n      { label: 'Delete', value: 'delete', variant: 'danger' }\n    ]\n  }\n];\n\ntable = new TableFieldDto(columns, userData, false);\n\n// In your component class\nonRowMenuAction(event: { action: string; row: any }) {\n  if (event.action === 'edit') {\n    // handle edit\n  } else if (event.action === 'delete') {\n    // handle delete\n  }\n}\n```\n\n```html\n\u003clite-table [table]=\"table\" (menuAction)=\"onRowMenuAction($event)\"\u003e\u003c/lite-table\u003e\n```\n\n### LitePanel Component\n\n**Selector:** `lite-panel`\n\n| Input | Type | Default | Description |\n| :---- | :--- | :------ | :---------- |\n| `title` | `string \\| null` | `null` | Panel header title text |\n| `content` | `string \\| TemplateRef \\| Type\u003cany\u003e \\| null` | `null` | Content to display: string, template, or component |\n| `contentInputs` | `Record\u003cstring, any\u003e \\| null` | `null` | Inputs to pass to dynamic component content |\n| `actions` | `LitePanelAction[] \\| null` | `null` | Action buttons (defaults to single OK button) |\n| `closeOnOverlayClick` | `boolean` | `true` | Whether clicking backdrop closes the panel |\n| `width` | `string \\| number \\| null` | `null` | Panel width (numeric values get px suffix) |\n| `height` | `string \\| number \\| null` | `null` | Panel height (numeric values get px suffix) |\n| `maxWidth` | `string \\| number \\| null` | `null` | Maximum panel width |\n| `maxHeight` | `string \\| number \\| null` | `null` | Maximum panel height |\n\n| Output | Type | Description |\n| :----- | :--- | :---------- |\n| `closed` | `unknown \\| null` | Emitted when panel closes with action value or null |\n\n**Features:**\n- Three content types: string, Angular template, or dynamic component\n- Configurable action buttons with variants (primary, secondary, danger)\n- Customizable dimensions with automatic px suffix for numbers\n- Backdrop click to close (configurable)\n- Close button in header\n- Component content with input binding support\n- Accessible with ARIA attributes\n\n**String Content Example:**\n```typescript\npanelOpen = signal(false);\n\nopenPanel() {\n  this.panelOpen.set(true);\n}\n\nonPanelClosed(result: unknown | null) {\n  this.panelOpen.set(false);\n}\n```\n\n```html\n@if (panelOpen()) {\n  \u003clite-panel\n    [title]=\"'Information'\"\n    [content]=\"'This is simple text content.'\"\n    (closed)=\"onPanelClosed($event)\"\u003e\n  \u003c/lite-panel\u003e\n}\n```\n\n**Template Content Example:**\n```typescript\npanelActions: LitePanelAction[] = [\n  { label: 'Confirm', value: 'confirm', variant: 'primary' },\n  { label: 'Cancel', value: null, variant: 'secondary' }\n];\n```\n\n```html\n@if (panelOpen()) {\n  \u003clite-panel\n    [title]=\"'Confirmation'\"\n    [content]=\"confirmTemplate\"\n    [actions]=\"panelActions\"\n    width=\"500px\"\n    (closed)=\"onPanelClosed($event)\"\u003e\n  \u003c/lite-panel\u003e\n}\n\n\u003cng-template #confirmTemplate let-close=\"close\"\u003e\n  \u003cp\u003eAre you sure you want to proceed?\u003c/p\u003e\n  \u003cbutton (click)=\"close('custom-value')\"\u003eCustom Action\u003c/button\u003e\n\u003c/ng-template\u003e\n```\n\n**Component Content Example:**\n```typescript\nimport { Component, Type } from '@angular/core';\nimport { FormControl, Validators } from '@angular/forms';\nimport { LiteInput, FieldDto } from 'ngx-lite-form';\n\n// Create a standalone component for panel content\n@Component({\n  selector: 'user-form',\n  standalone: true,\n  imports: [LiteInput],\n  template: `\n    \u003cdiv class=\"form-content\"\u003e\n      \u003cp\u003eFill out the form below:\u003c/p\u003e\n      \u003clite-input [control]=\"nameField\"\u003e\u003c/lite-input\u003e\n      \u003clite-input [control]=\"emailField\"\u003e\u003c/lite-input\u003e\n    \u003c/div\u003e\n  `\n})\nexport class UserFormComponent {\n  nameField = new FieldDto('Name', new FormControl('', [Validators.required]));\n  emailField = new FieldDto('Email', new FormControl('', [Validators.required, Validators.email]));\n}\n\n// In your main component\nuserFormComponent: Type\u003cany\u003e = UserFormComponent;\npanelActions: LitePanelAction[] = [\n  { label: 'Submit', value: 'submit', variant: 'primary' },\n  { label: 'Cancel', value: null, variant: 'secondary' }\n];\n```\n\n```html\n@if (panelOpen()) {\n  \u003clite-panel\n    [title]=\"'User Registration'\"\n    [content]=\"userFormComponent\"\n    [actions]=\"panelActions\"\n    width=\"600px\"\n    maxHeight=\"80vh\"\n    (closed)=\"onPanelClosed($event)\"\u003e\n  \u003c/lite-panel\u003e\n}\n```\n\n**Passing Inputs to Component Content:**\n```typescript\n// Component with inputs\n@Component({...})\nexport class DataViewComponent {\n  @Input() userId!: number;\n  @Input() mode!: string;\n}\n\n// Usage\ncomponentInputs = { userId: 123, mode: 'edit' };\n```\n\n```html\n\u003clite-panel\n  [content]=\"dataViewComponent\"\n  [contentInputs]=\"componentInputs\"\n  (closed)=\"onPanelClosed($event)\"\u003e\n\u003c/lite-panel\u003e\n```\n\n### LiteLoading Component\n\n**Selector:** `lite-loading`\n\n| Input      | Type                            | Default     | Description                                                  |\n| :--------- | :------------------------------ | :---------- | :----------------------------------------------------------- |\n| `view`     | `'spinner' \\| 'progress'`       | `'spinner'` | The view type: spinner for loading wheel, progress for bar. |\n| `progress` | `number \\| undefined`           | `undefined` | Progress percentage (0-100). Undefined shows indeterminate.  |\n| `message`  | `string \\| undefined`           | `undefined` | Optional message to display below the indicator.             |\n| `size`     | `'small' \\| 'medium' \\| 'large'`| `'medium'`  | Size of the spinner (only applies to spinner view).          |\n| `visible`  | `boolean`                       | `true`      | Whether the loading indicator is visible.                    |\n\n**Features:**\n- View toggle between spinner (loading wheel) and progress bar\n- Defined progress with percentage display (0-100%)\n- Indeterminate progress with animated sliding bar\n- Three spinner sizes: small, medium, large\n- Optional message display below indicator\n- Visibility control for conditional rendering\n- Smooth animations and transitions\n- Accessible with ARIA attributes\n\n**Example:**\n```typescript\n// Component\nimport { signal } from '@angular/core';\n\nisLoading = signal(true);\nuploadProgress = signal(0);\n\n// Simulate progress\nstartUpload() {\n  this.uploadProgress.set(0);\n  const interval = setInterval(() =\u003e {\n    const current = this.uploadProgress();\n    if (current \u003e= 100) {\n      clearInterval(interval);\n      this.isLoading.set(false);\n    } else {\n      this.uploadProgress.set(current + 10);\n    }\n  }, 300);\n}\n```\n\n```html\n\u003c!-- Basic spinner --\u003e\n\u003clite-loading\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Spinner with message and size --\u003e\n\u003clite-loading \n  [size]=\"'large'\" \n  [message]=\"'Loading data...'\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Defined progress bar --\u003e\n\u003clite-loading \n  [view]=\"'progress'\" \n  [progress]=\"uploadProgress()\" \n  [message]=\"'Uploading files...'\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Indeterminate progress bar --\u003e\n\u003clite-loading \n  [view]=\"'progress'\" \n  [message]=\"'Processing your request...'\\\"\u003e\u003c/lite-loading\u003e\n\n\u003c!-- Controlled visibility --\u003e\n\u003clite-loading \n  [visible]=\"isLoading()\" \n  [message]=\"'Please wait...'\"\u003e\u003c/lite-loading\u003e\n```\n\n### LitePaginator Component\n\n**Selector:** `lite-paginator`\n\n| Input       | Type                | Default | Description                                      |\n| :---------- | :------------------ | :------ | :----------------------------------------------- |\n| `paginator` | `PaginatorFieldDto` | -       | Paginator configuration object.                  |\n\n| Output               | Type     | Description                                      |\n| :------------------- | :------- | :----------------------------------------------- |\n| `pageChange`         | `number` | Emitted with the new page number on page change. |\n| `itemsPerPageChange` | `number` | Emitted with the new items-per-page count.     |\n\n**Features:**\n- Previous/Next navigation buttons with disabled states\n- Numbered page buttons with active state highlighting\n- Items per page dropdown selection\n- Total items display with customizable formatting\n- Keyboard navigation support (arrow keys)\n- Responsive design that adapts to different screen sizes\n- Accessibility features with ARIA labels and screen reader support\n- Configurable page range display and navigation controls\n\n**Example:**\n```typescript\n// Component\nimport { PaginatorFieldDto } from 'ngx-lite-form';\n\npaginator = new PaginatorFieldDto(1, 500, 25); // Page 1, 500 total items, 25 per page\n\n// Template\n\u003clite-paginator\n  [paginator]=\"paginator\"\n  (pageChange)=\"onPageChange($event)\"\n  (itemsPerPageChange)=\"onItemsPerPageChange($event)\"\u003e\n\u003c/lite-paginator\u003e\n```\n\n## Snackbar Service\n\nThe library provides a simple snackbar notification service for showing messages at the top of the page. No component or template is needed.\n\n### Usage\n\nInject the service and call `show()` with your message and type:\n\n```typescript\nimport { LiteSnackbarService } from 'ngx-lite-form';\n\nconstructor(private snackbar: LiteSnackbarService) {}\n\n// Show a success message\nthis.snackbar.show('Operation completed!', 'done');\n\n// Show a warning\nthis.snackbar.show('Please check your input.', 'warn');\n\n// Show an error (with custom duration)\nthis.snackbar.show('Something went wrong.', 'error', 5000);\n```\n\n- Types: `'done' | 'warn' | 'error'`\n- Duration: Optional, in milliseconds (default: 3000)\n\nThe snackbar will appear at the top of the page and auto-dismiss.\n\n---\n\n## Data Transfer Objects (DTOs)\n\n### FieldDto\nBasic field configuration for input and textarea components.\n\n```typescript\nclass FieldDto {\n  label: string;\n  formControl: FormControl;\n  rows?: number; // For textarea only\n}\n```\n\n### BaseSelectFieldDto\u003cT\u003e\nAbstract base class for select components.\n\n```typescript\nabstract class BaseSelectFieldDto\u003cT\u003e {\n  label: string;\n  options: T[];\n  displayWith: (option: T) =\u003e string;\n}\n```\n\n### SelectFieldDto\u003cT\u003e\nSingle-selection dropdown configuration.\n\n```typescript\nclass SelectFieldDto\u003cT\u003e extends BaseSelectFieldDto\u003cT\u003e {\n  formControl: FormControl\u003cT\u003e;\n}\n```\n\n### MultiSelectFieldDto\u003cT\u003e\nMulti-selection dropdown configuration.\n\n```typescript\nclass MultiSelectFieldDto\u003cT\u003e extends BaseSelectFieldDto\u003cT\u003e {\n  formControl: FormControl\u003cT[]\u003e;\n}\n```\n\n### DateRangeFieldDto\nDate range selection configuration.\n\n```typescript\ninterface DateRangeFieldDto extends Omit\u003cFieldDto, 'formControl'\u003e {\n  formControl: FormControl\u003cstring[]\u003e;\n}\n```\n\n### FileFieldDto\nFile field configuration for the LiteFile component.\n\n```typescript\nclass FileFieldDto {\n  label: string;\n  formControl: FormControl;\n  multiple?: boolean; // Allow multiple file selection (default: true)\n  accept?: string; // Accepted file types (default: '*/*')\n  maxFileSize?: number; // Maximum file size in bytes (default: 10MB)\n  maxFiles?: number; // Maximum number of files allowed (default: 10)\n  showPreview?: boolean; // Show image previews (default: true)\n}\n```\n\n### TableFieldDto\u003cT\u003e\nTable configuration for the LiteTable component.\n\n```typescript\nclass TableFieldDto\u003cT = any\u003e {\n  columns: TableColumn[];\n  data: T[];\n  showPaginator?: boolean;\n  paginatorConfig: PaginatorFieldDto;\n}\n\ninterface TableColumn {\n  key: string;              // Data property key (supports dot notation)\n  label: string;            // Column header text\n  flex?: string;            // CSS flex property (e.g., '0 0 100px', '1')\n  sortable?: boolean;       // Show sorting indicator\n  cellTemplate?: (value: any, row: any) =\u003e string; // Custom HTML template\n  type?: 'text' | 'menu';   // Optional column type (default: 'text')\n  menuItems?: Array\u003c{ label: string; value: string; variant?: 'danger' | 'default' }\u003e; // For 'menu' type columns\n}\n```\n\n### PaginatorFieldDto\nPagination configuration for table and standalone pagination components.\n\n```typescript\nclass PaginatorFieldDto {\n  currentPage: number;\n  totalItems: number;\n  itemsPerPage: number;\n}\n```\n\n---\n\n## Validation\n\nAll components support Angular Reactive Forms validation:\n\n```typescript\nimport { Validators } from '@angular/forms';\n\n// Required field\nemailField = new FieldDto(\n  'Email',\n  new FormControl('', [Validators.required, Validators.email])\n);\n\n// Custom validation\npasswordField = new FieldDto(\n  'Password',\n  new FormControl('', [\n    Validators.required,\n    Validators.minLength(8),\n    this.customPasswordValidator\n  ])\n);\n```\n\nError messages are automatically displayed below invalid fields.\n\n---\n\n## Styling and Customization\n\n### Default Styling\nThe library includes pre-built SCSS styles that provide:\n- Floating label animations\n- Focus states and transitions\n- Error styling\n- Responsive design\n\n### Custom Styling\n- Follow the compact SCSS conventions described in [docs/STYLEGUIDE.md](https://github.com/liangk/lite-form/blob/main/docs/STYLEGUIDE.md).\n- Components expose BEM-style class names for targeted overrides.\n- Import `lite-styles.scss` to leverage shared design tokens and mixins.\n\n---\n\n## Development\nProject layout at a glance:\n\n```\nlite-form/\n├── projects/lite-form/       # Library source and public API\n├── projects/ui-sandbox/      # Demo application showcasing components\n├── docs/                     # Documentation, guides, and changelog\n└── scripts/                  # Build and publishing utilities\n\n## License\nThis project is licensed under the MIT License - see the [LICENSE](https://github.com/liangk/lite-form/blob/main/LICENSE) file for details.\n\n---\n## Changelog\n- See [docs/CHANGELOG.md](https://github.com/liangk/lite-form/blob/main/docs/CHANGELOG.md) for the full historical record, including the latest `v1.3.4` release with LitePanel enhancements (dynamic component content with `contentInputs`) and documentation cleanup.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliangk%2Flite-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliangk%2Flite-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliangk%2Flite-form/lists"}