npm package: @lumidev/aiknow-ui-shared
Description: The **AIKnow UI Shared Library** is a simple Angular component library built on top of **Angular Material**. It provides reusable UI elements including routing-aware breadcrumbs, custom dialogs, loading indicators, and more.
Latest version: 0.7.4

## AIKnow UI Shared Library

The **AIKnow UI Shared Library** is a simple Angular component library built on top of **Angular Material**. It provides reusable UI elements including routing-aware breadcrumbs, custom dialogs, loading indicators, and more.

It contains those components:
* `<lib-aiknow-accordion>`: an accordion component
* `<lib-aiknow-autocomplete>`: an autocomplete form allowing the user to choose between a set of objects (specifying which property of the objects has to be shown in the dropdown menu)
* `<lib-aiknow-breadcrumbs>`: a simple breadcrumbs module, based on data specified in the app-routing.module.ts file
* `<lib-aiknow-calendar>`: a simple full-page calendar module showing events
* `<lib-aiknow-confirmation-dialog>`: a dialog with a custom text asking user for a confirmation
* `<lib-aiknow-container-page>`: an empty page only containing a `<router-outlet>` tag
* `<lib-aiknow-dashboard>`: the skeleton of a page containing a <lib-aiknow-navbar> and a `<router-outlet>`
* `<lib-aiknow-dialog>`: a dialog to be open through our service AiknowDialogWrapperService
* `<lib-aiknow-editable-field>`, `<lib-aiknow-editable-text>`, `<lib-aiknow-editable-textarea>`: fields that show a content with the possibility to edit it through an edit icon
* `<lib-aiknow-entity-list>`: card list showing a series of entities, sortable and searchable
* `<lib-aiknow-error-card>`: a card being showned in the middle of the page to notify an error or a process being completed
* `<lib-aiknow-error-message>`: a small component to show an error, conceived to be used inside a `<lib-aiknow-dialog>`
* `<lib-aiknow-features-grid>`: a grid view of a series of features, useful as home page menu for a web application
* `<lib-aiknow-file-upload>`: a file upload input area ready to be inserted into forms
* `<lib-aiknow-hamburger-menu>` and `<lib-aiknow-hamburger-menu-button>`: a configurable hamburger menu
* `<lib-aiknow-image-upload-with-preview>`: a `<lib-aiknow-editable-field>` with a `<lib-aiknow-file-upload>` and a preview of the image
* `<lib-aiknow-information-dialog>`: a dialog with a custom text providing the user with an information
* `<lib-aiknow-loading>`: a loading spinner that shows a `<lib-aiknow-error-card>` in case there is an error loading data
* `<lib-aiknow-navbar>`: a navbar containing `<lib-aiknow-breadcrumbs>`, a profile menu and a `<router-outlet>`
* `<lib-aiknow-tag-chips>`: an input field allowing to add tags dynamically

---

### Details

#### Preliminary operations
In your application's global styles.css add the following variables specifications (you can change the colors and the font according to your preference):

```css
:root {
  --primary: #3243AD;
  --secondary: #6B7280;
  --secondary-light: #E5E7EB;
  --text: #141414;
  --text-light: #3c3c3c;
  --background: white;
  --components-background: #F9FAFB;
  --borders-color: #d1d5db;
  --warning: #d32316;
  --hover: #f0f0f0;
}

html,
body {
    font-family: Roboto, "Helvetica Neue", sans-serif;
}
```

In the main module of your application, add:
```ts
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
```
and import ```AiknowUiSharedModule```:
```ts
import { AiknowUiSharedModule } from '@lumidev/aiknow-ui-shared';
...
imports: [your other imports..., AiknowUiSharedModule]
```

In the index.html of your application, add in the ```<head>``` tag:
```html
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
```

In the ```angular.json``` styles sections, add in the "styles" section:
```ts
"@angular/material/prebuilt-themes/azure-blue.css"
```
And in the "assets" section:
```ts
{
  "glob": "**/*",
  "input": "./node_modules/@lumidev/aiknow-ui-shared/assets"
}
```
---

#### `<lib-aiknow-accordion>`

**Example:**

```html
<lib-aiknow-accordion>
  <lib-aiknow-accordion-title>
    Accordion Title
  </lib-aiknow-accordion-title>
  <lib-aiknow-accordion-buttons>
    [Insert action icon buttons here]
  </lib-aiknow-accordion-buttons>
  </lib-aiknow-accordion-buttons>
  <lib-aiknow-accordion-body>
    Accordion Body
  </lib-aiknow-accordion-body>
</lib-aiknow-accordion>
```

---

#### `<lib-aiknow-autocomplete>`

**Description:**
A dynamic autocomplete component for selecting an object from a list. The displayed property in the dropdown is configurable. The objects *must* have an `id` field, either number or string.

**Inputs:**

* `items`: `any[]` – List of objects to choose from.
* `propertyName`: `string` – Name of the property to be displayed in the suggestions.
* `fieldDescription`: `string` – Description label shown above the input field.
* `required`: `boolean` – Whether the input is mandatory.
* `disabled`: `boolean` – Whether the field is disabled.
* `defaultValue`: `any` – Initial selected item.
* `clearIcon`: `boolean` – Whether to show the "x" icon to clear the field.
* `hint`: `string` – If not null, it is added as hint under the field. In this case it is suggested to add margin-bottom to the field.

**Two-way Binding:**

* `[(chosenItemId)]`: ID of the selected item.

**Example:**

```html
<lib-aiknow-autocomplete 
  [required]="true" 
  [items]="itemsList" 
  [(chosenItemId)]="chosenItemId" 
  fieldDescription="ItemType"
  propertyName="name"
  [defaultValue]="defaultValue">
</lib-aiknow-autocomplete>
```

---

#### `<lib-aiknow-breadcrumbs>`

**Description:**
Breadcrumbs auto-generated from `app-routing.module.ts` data.

**Usage:**
Add `data: { breadcrumb: 'Label' }` to your routes and `<lib-aiknow-breadcrumbs></lib-aiknow-breadcrumbs>` to your navbar component.
Set `appName` and `baseUrl` if you need a basepath for homepage different than "/". The home icon will redirect to `baseUrl` and `appName` will correspond to the "/" url (both are optional).

**Routing Example:**

```ts
{ path: 'users', component: UsersComponent, data: { breadcrumb: 'Users' } }
```

**Component Example:**

```html
<lib-aiknow-breadcrumbs></lib-aiknow-breadcrumbs>
```

---

#### `<lib-aiknow-calendar>`

**Description:**
Full-page calendar module showing events.
Component created starting from [[this Angular Calendar](https://github.com/monsterlessonsacademy/monsterlessonsacademy/tree/472-angular-calendar-tutorial)].

**Component Usage:**

```html
<mat-card>
    <lib-aiknow-calendar [events]="events" (visibleDaysChange)="onVisibleDaysChange($event)" [isLoading]="isLoading" todayLabel="Today" />
</mat-card>
```
(todayLabel is optional)

```ts
import { VisibleDaysChange } from "@lumidev/aiknow-ui-shared";

events: Map<string, string[]> = new Map();

onVisibleDaysChange(change: VisibleDaysChange) {
  this.loadEvents(change.start.toISODate(), change.end.toISODate());
}
```

---

#### `<lib-aiknow-confirmation-dialog>`

**Description:**
A dialog with a custom text asking the user for a confirmation.

**Usage:**
```ts
    const dialogRef = this.dialog.open(AiknowConfirmationDialogComponent, {
      data: {
        title: 'Delete document',
        message: 'Are you sure that you want to delete this document?',
        cancelLabel: 'Cancel', //optional
        confirmLabel: 'Confirm' //optional
      }
    });
    dialogRef.afterClosed().subscribe(isConfirmed => {
      if (isConfirmed) {
        ...
      }
    });
```

---

#### `<lib-aiknow-container-page>`

**Description:**
A simple page component that only contains a `router-outlet`.

**Example:**

```ts
{
  path: 'configurations', 
  component: AiknowContainerPageComponent,
  children: [
    { path: '', component: ConfigurationsComponent, data: { breadcrumb: 'Company Configurations' } },
    { path: 'users', component: UserConfigurationComponent, data: { breadcrumb: 'User Configuration' } }
  ]
}
```

---

#### `<lib-aiknow-dashboard>`

**Description:**
A page component that includes a navbar and a `router-outlet`. Designed as the main container for authenticated areas.

To use it you will need to implement a custom `DashboardContainerComponent`, to specify dashboard buttons' behaviour.

**Inputs:**

* `username`: `string`
* `email`: `string`
* `notifications`: `UserNotification[]`
* `hasNewNotifications`: `boolean`
* `notificationsError`: `boolean`
* `configMenuItems`: `ConfigMenuItem[]`
* `changePasswordLabel`: `string` (optional)
* `logoutLabel`: `string` (optional)
* `noNotificationsLabel`: `string` (optional)
* `notificationsLoadingErrorLabel`: `string` (optional)
* `profileLabel`: `string` (optional)
* `notificationsLabel`: `string` (optional)
* `configurationsLabel`: `string` (optional)
* `enableNotifications`: `boolean` (optional)
* `enableProfile`: `boolean` (optional)
* `enableConfigMenu`: `boolean` (optional)
* `appName`: `string` (optional, see breadcrumbs component for details)
* `baseUrl`: `string` (optional, see breadcrumbs component for details)

**Outputs:**

* `openNotificationEvent`: `UserNotification`

**DashboardContainerComponent HTML Example:**

```html
<lib-aiknow-dashboard [username]="username" [email]="email" logoutLabel="Logout" [notifications]="notifications"
    [hasNewNotifications]="hasNewNotifications" [notificationsError]="notificationsError"
    (openNotificationEvent)="openNotification($event)"></lib-aiknow-dashboard>
```

**DashboardContainerComponent TS Example:**
```ts
export class DashboardContainerComponent {

  username: string;
  email: string;
  eventSubscription: Subscription | null = null;

  constructor(private authService: AuthService,
    private userInteractionService: AiknowUserInteractionService,
    private dialog: AiknowDialogWrapperService) { }

  ngOnInit(): void {
    this.username = this.authService.getUsername();
    this.email = this.authService.getEmail();
    this.eventSubscription = this.userInteractionService.events$.subscribe(event => {
      if (event == 'logout') {
        this.authService.logout();
      }
      if (event == 'resetPwd') {
        this.dialog.open(ChangePasswordDialogComponent);
      }
    });
  }

  ngOnDestroy(): void {
    this.eventSubscription?.unsubscribe();
  }

}
```

**DashboardContainerComponent Routing Usage Example:**
```ts
  { path: '', component: DashboardContainerComponent, children: [
      { path: '', component: HomeComponent }
    ]
  }
```

---

#### `<lib-aiknow-dialog>`

**Description:**
A customizable dialog layout with dedicated header, content, and footer areas.

**Usage:**
Open dialogs using the `AiknowDialogWrapperService`.

**Example Service Call:**

```ts
this.dialog.open(ChangePasswordDialogComponent);
```

**Template Example:**

```html
<lib-aiknow-dialog dialogTitle="Change password">
  <lib-aiknow-dialog-header>
    ...
  </lib-aiknow-dialog-header>
  <lib-aiknow-dialog-content>
    ...
  </lib-aiknow-dialog-content>
  <lib-aiknow-dialog-footer>
    ...
  </lib-aiknow-dialog-footer>
</lib-aiknow-dialog>
```

---

#### `<lib-aiknow-editable-field>`, `<lib-aiknow-editable-text>`, `<lib-aiknow-editable-textarea>`

**Description:**
Fields showing a content (generic, text, textarea) and letting the user modify it through an edit icon.

**Examples:**

```html
<lib-aiknow-editable-field label="Product" [(editMode)]="productEditMode" [editable]="isEditable"
    (saveEvent)="edit(chosenProduct)" (cancel)="cancel()" saveIcon="save" closeIcon="close">
    <lib-aiknow-editable-field-display-content>
        <span>{{ product.name }}</span>
    </lib-aiknow-editable-field-display-content>
    <lib-aiknow-editable-field-edit-content>
        <select [(ngModel)]="chosenProduct">
            <option *ngFor="let product of availableProducts" [value]="product.id">
                {{ product.name }}
            </option>
        </select>
    </lib-aiknow-editable-field-edit-content>
</lib-aiknow-editable-field>

<lib-aiknow-editable-text label="Customer" [text]="ticket.customer" [editable]="isEditable" [maxLength]="255"
  (textChange)="edit($event)"></lib-aiknow-editable-text>

<lib-aiknow-editable-textarea [text]="ticket.description" label="Description" [editable]="isEditable" [maxlength]="2000"
  (textChange)="edit($event)"></lib-aiknow-editable-textarea>
```

---
#### `<lib-aiknow-entity-list>`

**Example:**

```html
<lib-aiknow-entity-list [fields]="fields" [entities]="users"
    (entitiesLoad)="loadTableUsers($event)" [entitiesTotalElements]="usersTotalElements"
    [entitiesPageNumber]="usersPageNumber" [entitiesPageSize]="usersPageSize"
    noEntitiesLabel="No users found" [newEntityEnabled]="true"
    newEntityLabel="Add a new user" [deleteEntityEnabled]="true"
    (openEntityDetailEvent)="editUser($event)" (newEntityEvent)="newUser()"
    (deleteEntityEvent)="deleteUser($event)">
</lib-aiknow-entity-list>
```

```ts
fields: EntityField[] = [
  {
    name: 'username',
    label: 'Username',
    sortField: 'username',
    customTemplate: this.userFieldTemplate, //optional, to customize field value appearance
    customHandler: username => this.handleUsername(username) //optional, to customize field value shown text
  }
];

loadTableUsers(params: EntitiesReloadParams) {
  this.loadUsers(params.pageIndex, params.sortField, params.sortDirection, params.searchedText);
}
```

---
#### `<lib-aiknow-error-card>`

**Description:**
A card component to display error messages or process statuses.

**Inputs:**

* `processing`: `boolean` – Shows a processing status message layout instead of an error message layout.
* `autoRefresh`: `boolean` – In processing mode, if enabled it automatically refresh the page every 30 sec.

**Example:**

```html
<lib-aiknow-error-card>
  <lib-aiknow-error-card-content>
    <p class="error-text">Page not found</p>
    <p><a routerLink="/">Click here to return to the home page</a></p>
  </lib-aiknow-error-card-content>
</lib-aiknow-error-card>
```

With processing indicator:

```html
<lib-aiknow-error-card [processing]="true"></lib-aiknow-error-card>
```

---

#### `<lib-aiknow-error-message>`

**Description:**
A simple inline error message component for use in dialogs or forms.

**Inputs:**

* `message`: `string` – Error message text.
* `noIcon`: `boolean` – If true, hides the error icon.

**Example:**

```html
<lib-aiknow-error-message [message]="errorMessage" [noIcon]="true" *ngIf="errorMessage"></lib-aiknow-error-message>
```

---

#### `<lib-aiknow-file-upload>`

**Description:**
An input area component allowing to upload a file.

**Inputs:**

* `uploadType`: `string` – If the value is `image`, it checks the filetype, else use `generic` as value.
* `multipleFileUploadLabelPart1`: `string` (optional)
* `multipleFileUploadLabelPart2`: `string` (optional)
* `singleFileUploadLabelPart2`: `string` (optional)
* `singleFileUploadLabelPart2`: `string` (optional)

**Two-way Binding:**

* `[(files)]`: The selected tags (array of strings).
* `[(fileEdited)]`: Indicates whether the file were edited.
* `[multipleUploads]`: If true, multiple uploads at time are allowed (default: false).

**Example:**

```html
<lib-aiknow-file-upload [(files)]="files" [(fileEdited)]="fileEdited" uploadType="generic"></lib-aiknow-file-upload>
```

---

#### `<lib-aiknow-editable-field>`

**Description:**
A `<lib-aiknow-editable-field>` with a `<lib-aiknow-file-upload>` and a preview of the image

**Example:**

```html
<lib-aiknow-image-upload-with-preview [(files)]="images" [(editMode)]="imageEditMode"
    [url]="logoUrl" alt="Uploaded image"
    noImageLabel="No uploaded image" (saveEvent)="saveImage()"
    singleFileUploadLabelPart1="Drag here a file or"
    singleFileUploadLabelPart2="upload a file from PC"></lib-aiknow-image-upload-with-preview>
```

---

---

#### `<lib-aiknow-features-grid>`

**Example**

```html
<lib-aiknow-features-grid [features]="homeElements"></lib-aiknow-features-grid>
```

```ts
homeElements: Feature[] = [
  {
    icon: 'account_circle',
    label: 'Profile',
    url: 'profile',
    description: 'Handle your user details'
  }];
```

---

#### `<lib-aiknow-hamburger-menu>` and `<lib-aiknow-hamburger-menu-button>`

**Example:**
```html
<lib-aiknow-hamburger-menu [menuTemplate]="profileMenu" [open]="profileMenuOpened"
    (menuOpened)="onMenuOpen('profile')">
    <mat-icon fontIcon="account_circle"></mat-icon>
    <span class="menu-title">{{ profileLabel }}</span>
</lib-aiknow-hamburger-menu>

<ng-template #profileMenu>
    <div cdkMenu>
        <div class="profile-info">
            <p class="profile-username">{{ username }}</p>
            <p class="profile-email">{{ email }}</p>
        </div>
        <lib-aiknow-hamburger-menu-button (click)="logout()" cdkMenuItem>
            {{ logoutLabel }}
        </lib-aiknow-hamburger-menu-button>
    </div>
</ng-template>
```

---

#### `<lib-aiknow-information-dialog>`

**Description:**
A dialog with a custom text providing the user with an information.

**Usage:**
```ts
      this.dialog.open(AiknowInformationDialogComponent, {
        data: {
          title: 'Delete document error',
          message: 'There was an error deleting the document",
          okLabel: 'Ok' //optional
        }
      });
```

---

#### `<lib-aiknow-loading>`

**Description:**
A loading spinner with optional error fallback.

**Inputs:**

* `enabled`: `boolean` – Show/hide loading spinner.
* `loadingError`: `boolean` – If true, shows an error card instead.
* `authLoadingError`: `boolean` – If true, shows an error card concerning authentication.
* `fixedHeight`: `boolean` – If true, enforces a fixed-height layout.
* `errorLabel`: `string` (optional)
* `authErrorLabel`: `string` – (optional)
* `backToHomeLabel`: `string` (optional)
* `refreshEnabled`: `boolean` – If true, the user is offered with the option to repeat the API call that was in error. Catch `(refreshClicked)` event output.
* `refreshLabel`: `string` (optional)

**Example:**

```html
<lib-aiknow-loading [enabled]="isLoading" [loadingError]="loadingError"></lib-aiknow-loading>
```

---

#### `<lib-aiknow-navbar>`

**Description:**
A top navigation bar that includes breadcrumbs and user profile information.

**Inputs:**

* `username`: `string`
* `email`: `string`
* `notifications`: `UserNotification[]`
* `configMenuItems`: `ConfigMenuItem[]`
* `hasNewNotifications`: `boolean`
* `notificationsError`: `boolean`
* `changePasswordLabel`: `string` (optional)
* `logoutLabel`: `string` (optional)
* `noNotificationsLabel`: `string` (optional)
* `profileLabel`: `string` (optional)
* `notificationsLabel`: `string` (optional)
* `configurationsLabel`: `string` (optional)
* `enableNotifications`: `boolean` (optional)
* `enableProfile`: `boolean` (optional)
* `enableConfigMenu`: `boolean` (optional)
* `notificationsLoadingErrorLabel`: `string` (optional)
* `appName`: `string` (optional, see breadcrumbs component for details)
* `baseUrl`: `string` (optional, see breadcrumbs component for details)

**Outputs:**

* `openNotificationEvent`: `UserNotification`

**Notification Dto**
```ts
export interface UserNotification {
  id: number;
  message: string;
  url: string;
  unread: boolean;
}
```

**Example:**

```html
  <lib-aiknow-navbar [username]="username" [email]="email" [notifications]="notifications"
    [hasNewNotifications]="hasNewNotifications" [notificationsError]="notificationsError"
    (openNotificationEvent)="openNotification($event)" [logoutLabel]="logoutLabel"
    [changePasswordLabel]="changePasswordLabel" [noNotificationsLabel]="noNotificationsLabel"
    [notificationsLoadingErrorLabel]="notificationsLoadingErrorLabel"></lib-aiknow-navbar>
```

---

#### `<lib-aiknow-tag-chips>`

**Description:**
An input field component allowing the dynamic insertion of tags.

**Two-way Binding:**

* `[(selectedTags)]`: The selected tags (array of strings).

**Example:**

```html
<lib-aiknow-tag-chips [(selectedTags)]="selectedTags" newTagLabel="New tag..."></lib-aiknow-tag-chips>
```
(newTagLabel is optional)