# NG Prime Tools

An advanced PrimeNG tools library for Angular.

## Table of Contents

- [Introduction](#introduction)
- [Installation](#installation)
- [Compatibility](#compatibility)
- [Usage](#usage)
  - [pt-advanced-prime-table](#pt-advanced-prime-table)
    - [Inputs](#inputs)
    - [Outputs](#outputs)
    - [Example](#example)
  - [multi-search-criteria](#multi-search-criteria)
    - [Inputs](#inputs-1)
    - [Outputs](#outputs-1)
    - [Example](#example-1)
  - [FormBuilder](#formbuilder)
    - [Components](#components)
    - [Example](#example-2)
- [Changelog](#changelog)
- [License](#license)

## Introduction

`ng-prime-tools` is a collection of advanced tools built on top of PrimeNG for Angular applications.

To include the necessary steps for installing `ng-prime-tools` along with its dependencies, you can update the installation instructions as follows:

## Installation

To install `ng-prime-tools` and its necessary dependencies, use the following commands:

```bash
npm install ng-prime-tools
npm install chart.js chartjs-plugin-datalabels
```

This ensures that all required libraries are properly installed and available for use in your project.

## Compatibility

- **Angular Version**: 17.3.1 or higher
- **PrimeNG Version**: 17.18.0 or higher

## Usage

### pt-advanced-prime-table

To use the `pt-advanced-prime-table` component, follow these steps:

1. **Import the Module:**

   Import the `NgAdvancedPrimeTableModule` in your Angular module or standalone component.

   ```typescript
   import { NgAdvancedPrimeTableModule, TableColumn, TableTypeEnum } from "ng-prime-tools";
   ```

2. **Add the Component:**

   Add the `pt-advanced-prime-table` component to your template:

   ```html
   <pt-advanced-prime-table [columns]="columns" [data]="data" [hasSearchFilter]="true" [hasColumnFilter]="true" [isPaginated]="true" [totalRecords]="totalRecords" [isSortable]="true"></pt-advanced-prime-table>
   ```

3. **Define the Inputs:**

   In your component, define the necessary inputs for the table:

   ```typescript
   import { Component, OnInit } from "@angular/core";
   import { NgAdvancedPrimeTableModule } from "ng-prime-tools/pt-advanced-prime-table";
   import { TableColumn } from "ng-prime-tools/models";
   import { TableTypeEnum } from "ng-prime-tools/enums";

   @Component({
     selector: "app-root",
     standalone: true,
     imports: [NgAdvancedPrimeTableModule],
     templateUrl: "./app.component.html",
     styleUrls: ["./app.component.css"],
   })
   export class AppComponent implements OnInit {
     columns: TableColumn[] = [];
     data: any[] = [];
     totalRecords: number = 0;

     ngOnInit(): void {
       this.columns = [
         {
           title: "Name",
           code: "name",
           type: TableTypeEnum.STRING,
           isEditable: true,
         },
         {
           title: "Date",
           code: "date",
           type: TableTypeEnum.DATE,
           isEditable: true,
         },
         {
           title: "Amount",
           code: "amount",
           type: TableTypeEnum.AMOUNT,
           currency: "USD",
           isEditable: true,
         },
       ];

       this.data = [
         { name: "John Doe", date: "11/06/2024", amount: 100 },
         { name: "Jane Doe", date: "20/06/2024", amount: 200 },
       ];

       this.totalRecords = this.data.length;
     }
   }
   ```

### Inputs

- **data** (`any[]`): The data to be displayed in the table.
- **columns** (`TableColumn[]`): The columns configuration for the table.
- **totalRecords** (`number`): The total number of records.
- **rowsPerPage** (`number[]`): The number of rows per page options for pagination.
- **hasSearchFilter** (`boolean`): Whether the table has a global search filter.
- **hasColumnFilter** (`boolean`): Whether the table has column-specific filters.
- **isPaginated** (`boolean`): Whether the table is paginated.
- **actions** (`any[]`): The actions available for the table rows.
- **isSortable** (`boolean`): Whether the table columns are sortable.

### Outputs

- **filter** (`EventEmitter`): Emitted when the table is filtered.
- **search** (`EventEmitter<any>`): Emitted when a global search is performed.

### Example

Here's a complete example of how to use the `pt-advanced-prime-table` component:

```typescript
import { Component, OnInit } from "@angular/core";
import { CommonModule } from "@angular/common";
import { NgAdvancedPrimeTableModule } from "ng-prime-tools/pt-advanced-prime-table";
import { TableColumn } from "ng-prime-tools/models";
import { TableTypeEnum } from "ng-prime-tools/enums";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [CommonModule, NgAdvancedPrimeTableModule],
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
  columns: TableColumn[] = [];
  data: any[] = [];
  totalRecords: number = 0;

  ngOnInit(): void {
    this.columns = [
      {
        title: "Name",
        code: "name",
        type: TableTypeEnum.STRING,
        isEditable: true,
      },
      {
        title: "Date",
        code: "date",
        type: TableTypeEnum.DATE,
        isEditable: true,
      },
      {
        title: "Amount",
        code: "amount",
        type: TableTypeEnum.AMOUNT,
        currency: "USD",
        isEditable: true,
      },
    ];

    this.data = [
      { name: "ZAK JAAI", date: "11/06/2024", amount: 100 },
      { name: "ZAK2 JAAI", date: "20/06/2024", amount: 200 },
    ];

    this.totalRecords = this.data.length;
  }
}
```

```html
<pt-advanced-prime-table [columns]="columns" [data]="data" [hasSearchFilter]="true" [hasColumnFilter]="true" [isPaginated]="true" [totalRecords]="totalRecords" [isSortable]="true"></pt-advanced-prime-table>
```

### multi-search-criteria

To use the `multi-search-criteria` component, follow these steps:

1. **Import the Module:**

   Import the `MultiSearchCriteriaModule` in your Angular module or standalone component.

   ```typescript
   import { MultiSearchCriteriaModule, SearchCriteria, SearchCriteriaTypeEnum } from "ng-prime-tools";
   ```

2. **Add the Component:**

   Add the `multi-search-criteria` component to your template:

   ```html
   <multi-search-criteria [title]="'Multi-Criteria Search'" [criteria]="criteria" [data]="data" [mode]="'dynamic'" (filteredData)="onFilteredData($event)" (searchCriteria)="onSearchData($event)"></multi-search-criteria>
   ```

3. **Define the Inputs:**

   In your component, define the necessary inputs for the criteria:

   ```typescript
   import { Component, OnInit } from "@angular/core";
   import { CommonModule } from "@angular/common";
   import { MultiSearchCriteriaModule, SearchCriteria, SearchCriteriaTypeEnum, FilterOption } from "ng-prime-tools";

   @Component({
     selector: "app-root",
     standalone: true,
     imports: [CommonModule, MultiSearchCriteriaModule],
     templateUrl: "./app.component.html",
     styleUrls: ["./app.component.css"],
   })
   export class AppComponent implements OnInit {
     criteria: SearchCriteria[] = [];
     data: any[] = [];
     filteredData: any[] = [];
     totalRecords: number = 0;

     ngOnInit(): void {
       this.criteria = [
         {
           title: "Name",
           code: "name",
           type: SearchCriteriaTypeEnum.STRING,
         },
         {
           title: "Date Range",
           code: "dateRange",
           type: SearchCriteriaTypeEnum.DATERANGE,
         },
         {
           title: "Amount",
           code: "amount",
           type: SearchCriteriaTypeEnum.AMOUNT,
           currency: "USD",
         },
         {
           title: "Type",
           code: "type",
           type: SearchCriteriaTypeEnum.MULTISELECT,
           filterOptions: [
             { label: "Invoice", value: "Invoice" },
             { label: "Bill", value: "Bill" },
           ],
         },
       ];

       this.data = [
         { name: "ZAK JAAI", date: "11/06/2024", amount: 100, type: "Invoice" },
         { name: "ZAK2 JAAI", date: "20/06/2024", amount: 200, type: "Bill" },
       ];

       this.filteredData = [...this.data];
       this.totalRecords = this.data.length;
     }

     onFilteredData(filteredData: any[]): void {
       this.filteredData = filteredData;
       this.totalRecords = filteredData.length;
     }

     onSearchData(searchCriteria: { [key: string]: any }): void {
       console.log(searchCriteria);
     }
   }
   ```

### Inputs

- **title** (`

string`): The title of the multi-search criteria panel.

- **criteria** (`SearchCriteria[]`): The search criteria configuration.
- **data** (`any[]`): The data to be filtered (used in static mode).
- **mode** (`'static' | 'dynamic'`): The mode of the multi-search criteria component.
  - `'static'`: Filters the data directly within the component.
  - `'dynamic'`: Emits the search criteria to be handled externally (e.g., for server-side filtering).

### Outputs

- **filteredData** (`EventEmitter<any[]>`): Emitted with the filtered data (only in static mode).
- **searchCriteria** (`EventEmitter<{ [key: string]: any }>`): Emitted with the search criteria (only in dynamic mode).

### Example

Here's a complete example of how to use the `multi-search-criteria` component in dynamic mode:

```typescript
import { Component, OnInit } from "@angular/core";
import { CommonModule } from "@angular/common";
import { MultiSearchCriteriaModule, SearchCriteria, SearchCriteriaTypeEnum, FilterOption } from "ng-prime-tools";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [CommonModule, MultiSearchCriteriaModule],
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent implements OnInit {
  criteria: SearchCriteria[] = [];
  data: any[] = [];
  filteredData: any[] = [];
  totalRecords: number = 0;

  ngOnInit(): void {
    this.criteria = [
      {
        title: "Name",
        code: "name",
        type: SearchCriteriaTypeEnum.STRING,
      },
      {
        title: "Date Range",
        code: "dateRange",
        type: SearchCriteriaTypeEnum.DATERANGE,
      },
      {
        title: "Amount",
        code: "amount",
        type: SearchCriteriaTypeEnum.AMOUNT,
        currency: "USD",
      },
      {
        title: "Type",
        code: "type",
        type: SearchCriteriaTypeEnum.MULTISELECT,
        filterOptions: [
          { label: "Invoice", value: "Invoice" },
          { label: "Bill", value: "Bill" },
        ],
      },
    ];

    this.data = [
      { name: "ZAK JAAI", date: "11/06/2024", amount: 100, type: "Invoice" },
      { name: "ZAK2 JAAI", date: "20/06/2024", amount: 200, type: "Bill" },
    ];

    this.filteredData = [...this.data];
    this.totalRecords = this.data.length;
  }

  onFilteredData(filteredData: any[]): void {
    this.filteredData = filteredData;
    this.totalRecords = filteredData.length;
  }

  onSearchData(searchCriteria: { [key: string]: any }): void {
    console.log(searchCriteria);
    // Perform server-side search or any other external data fetching logic
  }
}
```

```html
<multi-search-criteria [title]="'Multi-Criteria Search'" [criteria]="criteria" [data]="data" [mode]="'dynamic'" (filteredData)="onFilteredData($event)" (searchCriteria)="onSearchData($event)"></multi-search-criteria>

<pt-advanced-prime-table [columns]="columns" [data]="filteredData" [hasSearchFilter]="true" [hasColumnFilter]="true" [isPaginated]="true" [totalRecords]="totalRecords" [isSortable]="true"></pt-advanced-prime-table>
```

### FormBuilder

The `FormBuilder` component is a powerful and flexible tool for dynamically generating forms with various input types. It allows you to create nested groups, manage validations, and customize the appearance and behavior of your forms.

#### Components

The `FormBuilder` leverages several input components to build comprehensive forms:

- **`pt-check-box-input`**: A customizable checkbox input component.
- **`pt-date-input`**: A versatile date input component supporting both single date and date range selections.
- **`pt-dropdown`**: A dropdown input component for selecting from a list of options.
- **`pt-form-builder`**: The form builder component that dynamically renders form fields.
- **`pt-multi-select`**: A multi-select dropdown component for selecting multiple values from a list.
- **`pt-number-input`**: A numeric input component with support for validation and formatting.
- **`pt-switch-input`**: A switch input component, ideal for toggling settings.
- **`pt-text-area-input`**: A text area input component for larger, multi-line text entries.
- **`pt-text-input`**: A standard text input component with support for icons, placeholders, and validation.

#### Example

Below is an example of how to use the `FormBuilder` component to create a user registration form with various input fields:

```typescript
import { Component, OnInit } from "@angular/core";
import { CommonModule } from "@angular/common";
import { ReactiveFormsModule } from "@angular/forms";
import { FormFieldGroup, FormInputTypeEnum, ButtonColorEnum, FormButton, PTFormBuilderModule, InputValidationEnum, FormTextField, FormCheckBoxField, FormSwitchField, FormNumberField, FormDateField, FormDropdownField, FormMultiSelectField, FormTextAreaField } from "ng-prime-tools";

@Component({
  selector: "app-form-builder-tester",
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, PTFormBuilderModule],
  templateUrl: "./form-builder-tester.component.html",
  styleUrls: ["./form-builder-tester.component.css"],
})
export class FormBuilderTesterComponent implements OnInit {
  mainGroup: FormFieldGroup = { fields: [], groups: [] };
  buttons: FormButton[] = [];

  ngOnInit() {
    this.initializeSettings();
  }

  initializeSettings() {
    this.initializeMainGroup();
    this.initializeButtons();
  }

  initializeMainGroup() {
    this.mainGroup = {
      groups: [this.createNameGroup(), this.createSubscriptionGroup(), this.createAgeGroup(), this.createBirthdateGroup(), this.createDateRangeGroup(), this.createAmountGroup(), this.createCountryGroup(), this.createHobbiesGroup(), this.createDescriptionGroup()],
    };
  }

  createNameGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.TEXT,
          label: "First Name",
          name: "firstName",
          required: true,
          placeholder: "Enter your first name",
          iconClass: "pi pi-user",
          iconPosition: "left",
          minLength: 3,
          maxLength: 10,
          inputValidation: InputValidationEnum.ONLY_LETTERS,
        } as FormTextField,
        {
          type: FormInputTypeEnum.TEXT,
          label: "Last Name",
          name: "lastName",
          required: true,
          placeholder: "Enter your last name",
        } as FormTextField,
      ],
    };
  }

  createSubscriptionGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.CHECKBOX,
          label: "Subscribe",
          name: "subscribe",
          required: true,
        } as FormCheckBoxField,
        {
          type: FormInputTypeEnum.SWITCH,
          label: "Active",
          name: "active",
          required: true,
        } as FormSwitchField,
      ],
    };
  }

  createAgeGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.NUMBER,
          label: "Age",
          name: "age",
          minValue: "18",
          maxValue: "40",
          required: true,
          errorText: "Age is required",
          placeholder: "Enter your age",
        } as FormNumberField,
      ],
    };
  }

  createBirthdateGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.DATE,
          label: "Birthdate",
          name: "birthdate",
          required: true,
          dateFormat: "dd/mm/yy",
          hourFormat: "24",
          placeholder: "Select your birthdate",
          dateInputType: "date",
        } as FormDateField,
      ],
    };
  }

  createDateRangeGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.DATE,
          label: "Date Range",
          name: "daterange",
          required: true,
          placeholder: "Select date range",
          dateInputType: "range",
        } as FormDateField,
      ],
    };
  }

  createAmountGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.AMOUNT,
          label: "Amount",
          name: "amount",
          minValue: "100",
          maxValue: "1000",
          required: true,
          currency: "MAD",
          iconPosition: "right",
          placeholder: "Enter the amount",
          decimalDigits: 3,
          numberFormat: "fr-FR",
          disabled: true,
        } as FormNumberField,
      ],
    };
  }

  createCountryGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.SELECT,
          label: "Country",
          name: "country",
          options: [
            { label: "USA", value: "usa" },
            { label: "Canada", value: "canada" },
          ],
          required: true,
          placeholder: "Select your country",
        } as FormDropdownField,
      ],
    };
  }

  createHobbiesGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.MULTISELECT,
          label: "Hobbies",
          name: "hobbies",
          options: [
            { label: "Reading", value: "reading" },
            { label: "Travelling", value: "travelling" },
            { label: "Cooking", value: "cooking" },
          ],
          required: true,
          placeholder: "Select your hobbies",
        } as FormMultiSelectField,
      ],
    };
  }

  createDescriptionGroup(): FormFieldGroup {
    return {
      fields: [
        {
          type: FormInputTypeEnum.TEXTAREA,
          label: "Description",
          name: "description",
          rows: 5,
          required: true,
          errorText: "Description est obligatoire !",
          placeholder: "Enter a description",
          minLength: 10,
          maxLength: 20,
          iconClass: "pi pi-dollar",
          iconPosition: "right",
          disabled: true,
        } as FormTextAreaField,
      ],
    };
  }

  initializeButtons() {
    this.buttons = [
      {
        text: "Custom Action",
        action: this.customAction,
        color: ButtonColorEnum.SUCCESS,
        icon: "pi pi-check",
      },
      { text: "Submit", color: ButtonColorEnum.PRIMARY, isSubmit: true },
      { text: "Clear", color: ButtonColorEnum.SECONDARY, isClear: true },
    ];
  }

  customAction() {
    console.log("Custom action executed");
  }

  onFormSubmit(formData: { [key: string]: any }) {
    console.log("Form submitted with data:", formData);
  }
}
```

## Changelog

### Version 1.0.31 - Release Date: 16/04/2025

- pt-advanced-table : Fixing the filters with asynchronous data and composed types.

### Version 1.0.30 - Release Date: 10/04/2025

- fixing the disabling btn in pt-login

### Version 1.0.28 - 1.O.29 - Release Date: 05/04/2025

- Changing style of pt-button when disabled

### Version 1.0.27 - Release Date: 27/03/2025

- adding pt-notifier
- fixing pt-dialog with ameliorations

### Version 1.0.26 - Release Date: 11/03/2025

- fixing pt-dialog with ameliorations

### Version 1.0.25 - Release Date: 06/03/2025

- adding pt-chart-comparison

### Version 1.0.24 - Release Date: 05/03/2025

- adding pt-group
- adding pt-metric-panel

### Version 1.0.23 - Release Date: 03/03/2025

- fix NUMBER type in advanced table

### Version 1.0.22 - Release Date: 03/03/2025

- adding styles for composed types in advanced table

### Version 1.0.21 - Release Date: 28/02/2025

- fix composed types in advanced table

### Version 1.0.20 - Release Date: 24/02/2025

- fixing error message in login page

### Version 1.0.19 - Release Date: 18/02/2025

- fixing scroll bar pt-card

### Version 1.0.18 - Release Date: 22/01/2025

- fixing search in sidebar position
- pt-card : adding background color transparency and pattern image transparency

### Version 1.0.17 - Release Date: 21/01/2025

- Adding positions for login page

### Version 1.0.16 - Release Date: 19/01/2025

- fix bug z-index fancy menu

### Version 1.0.15 - Release Date: 19/11/2024

- adding pt-line-chart

### Version 1.0.14 - Release Date: 15/11/2024

- fix metric-card 'fixedWidth' param
- adding design for icons in metric cards
- fix issue having multiple charts using pt-chart

### Version 1.0.13 - Release Date: 12/11/2024

- fix menu z-index
- adding parametrable toggle
- adding position param for background image in pt-card
- remove background transparency for pt-card

### Version 1.0.12 - Release Date: 28/09/2024

- fix background transparency for pt-card

### Version 1.0.11 - Release Date: 28/09/2024

- fix column width for advanced table

### Version 1.0.10 - Release Date: 25/09/2024

- **New Components:**

  - **`pt-bar`:** Introduced a new bar component to visually represent progress or metrics in a horizontal bar layout.
  - **`pt-text-input`:** Added a customizable text input component to handle various form input needs with validation and error handling.
  - **`pt-page-skeleton`:** Introduced a page skeleton component for loading states, offering a clean UI while data is being fetched.
  - **`pt-footer`:** A new footer component providing a customizable and responsive footer layout for pages.
  - **`pt-menu-fancy`:** Added a new fancy menu component for stylish navigation menus with enhanced layout options.
  - **`pt-button`:** Introduced a highly customizable button component with various styles, icons, and action support.
  - **`pt-dialog`:** Added a flexible dialog component for modal-based interactions, supporting customizable content, actions, and layout.

- **Enhancements to `pt-advanced-prime-table`:**
  - **Dynamic Column Width:** Enhanced the table to support dynamic column width adjustments based on content, ensuring alignment between header and body cells.
  - **Customizable Sticky Headers:** Improved sticky header behavior, allowing users to define `max-height` for tables with large datasets.
  - **Improved Icon Handling:** Optimized column and icon width calculations for better alignment and a more consistent visual experience.
  - **Cell Alignment Fixes:** Resolved issues with header and body cell misalignment when header content wraps.

### Version 1.0.9 - Release Date: 02/09/2024

- **`pt-advanced-prime-table`:**

  - **Loading Indicator:** Added loading spinner functionality to provide visual feedback during data fetching.
  - **Vertical Scrolling:** Enabled vertical scrolling to handle large datasets and improve usability.
  - **Empty Record Message:** Introduced a customizable message for when no data is available in the table.

- **`pt-metric-card-group` & `pt-metric-card`:** Introduced a new metric card component and its group, designed for displaying key performance indicators in a visually appealing way.
- **`pt-chart`:** Added a new chart component that supports various chart types (line, bar, doughnut, pie, etc.), with extensive customization options.
- **`pt-card`:** Introduced a new card component for displaying content within a bordered and customizable container.
- **`pt-menu`:** Added a new menu component to be used within cards, supporting various actions and a customizable layout.

#### Version 1.0.8

Fix bug on size of buttons exports

#### Version 1.0.7

Adding export to pdf and excel buttons in the `pt-advanced-prime-table`.

```
  [hasExportExcel]="true"
  [hasExportPDF]="true"
  (exportExcelEvent)="onExportExcel()"
  (exportPdfEvent)="onExportPDF()"
```

#### Version 1.0.6

- **FormBuilder Component:**  
  Introduced a powerful and flexible `FormBuilder` component that allows developers to dynamically create forms with various input types. The `FormBuilder` supports nested groups, input validation, and customizable form behavior. This component simplifies the process of building complex forms by providing a consistent and reusable structure.

- **New Input Components:**
  - **`pt-check-box-input`**: A customizable checkbox input component for boolean selections.
  - **`pt-date-input`**: A versatile date input component supporting both single date and date range selections with customizable formats.
  - **`pt-dropdown`**: A dropdown input component for selecting single options from a list.
  - **`pt-multi-select`**: A multi-select dropdown component for selecting multiple values from a list.
  - **`pt-number-input`**: A numeric input component with support for validation (e.g., min/max values) and formatting.
  - **`pt-switch-input`**: A switch input component for toggling between two states.
  - **`pt-text-area-input`**: A text area input component for multi-line text entries with customizable rows and validation.
  - **`pt-text-input`**: A standard text input component with support for icons, placeholders, and input validation.

### Version 1.0.5

- **`multi-search-criteria` Component**

  - Added support for `mode` input to handle dynamic and static filtering.
    - `mode` input can be set to `'dynamic'` or `'static'`. When set to `'dynamic'`, the component emits search criteria for backend filtering. When set to `'static'`, the component filters data locally.
  - Fixed the bug in the `selectAll` functionality for multi-select filters.
    - Users can select or deselect all options in a multi-select filter.

- **`pt-advanced-prime-table` Component**
  - Added support for customizable amount formatting.
    - New inputs for columns of type `AMOUNT`:
      - `thousandSeparator` (`comma` or `space`): Specifies the character used for thousands separator.
      - `decimalSeparator` (`comma` or `dot`): Specifies the character used for decimal separator.
    - Updated the `customCurrency` pipe to handle optional currency display and customizable separators.

### Version 1.0.4

- Added `multi-search-criteria` component.

### Version 1.0.3

- Initial release with `pt-advanced-prime-table` component.

## License

This project is licensed under the MIT License.
