npm package: @ruc-lib/widget
Description: This library provides a highly configurable widget component that allows for the creation of a dynamic, dashboard-like interface. Users can create, customize, and arrange multiple widgets within a container, with support for dragging, resizing, and dynami
Latest version: 4.0.0

# ruclib-widget

This library provides a highly configurable widget component that allows for the creation of a dynamic, dashboard-like interface. Users can create, customize, and arrange multiple widgets within a container, with support for dragging, resizing, and dynamic content.

## Features

- **Dynamic Creation**: Create any number of widgets, each with its own configuration and content.
- **Drag & Drop**: Easily rearrange widgets within the host container. Layout changes are emitted to be saved.
- **Resizing**: Set responsive width and height for each widget. Widgets can also be made resizable by the user.
- **Custom Content**:
  - Set a title and an optional header icon for each widget.
  - Embed custom components (like charts, graphs, forms, etc.) as widget content.
- **Interactivity**:
  - Optionally display a close icon to remove a widget from the layout.
  - Disable individual widgets to make them non-interactive.
- **Styling & Theming**:
  - Set a custom background color for each widget.
  - Apply custom theme classes for a consistent look and feel.
  - Visual feedback is provided when a widget is being dragged.
- **Layout Persistence**: The component emits an event with the updated widget configuration whenever a widget is moved or resized, allowing the application to save and restore the layout.

## Installation Guide

### Install the Entire Library
```bash
npm install @uxpractice/ruc-lib
```

### Install Individual Component

If you only need the Widget component:

**For Angular 15:**
```bash
npm install @ruc-lib/widget@3.2.0 @angular/material@^15.0.0 @angular/cdk@^15.0.0
```

**For Angular 16:**
```bash
npm install @ruc-lib/widget@3.2.0 @angular/material@^16.0.0 @angular/cdk@^16.0.0
```

**For Angular 17:**
```bash
npm install @ruc-lib/widget@4.0.0 @angular/material@^17.0.0 @angular/cdk@^17.0.0
```

**For Angular 18:**
```bash
npm install @ruc-lib/widget@4.0.0 @angular/material@^18.0.0 @angular/cdk@^18.0.0
```

**For Angular 19:**
```bash
npm install @ruc-lib/widget@4.0.0 @angular/material@^19.0.0 @angular/cdk@^19.0.0
```

**For Angular 20:**
```bash
npm install @ruc-lib/widget@4.0.0
```

> **Note:** When installing in Angular 15-19 apps, you must specify the matching `@angular/material` and `@angular/cdk` versions to avoid peer dependency conflicts. Angular 20 will automatically use the correct versions.


## Version Compatibility
 
Please ensure you install the correct version of `@ruc-lib/widget` based on your Angular version.
 
| Angular Version    | Compatible `@ruc-lib/widget` Version     |
|--------------------|------------------------------------------|
| 15.x.x             | `npm install @ruc-lib/widget@^3.2.0`     |
| 16.x.x             | `npm install @ruc-lib/widget@^3.2.0`     |
| 17.x.x             | `npm install @ruc-lib/widget@^4.0.0`     |
| 18.x.x             | `npm install @ruc-lib/widget@^4.0.0`     |
| 19.x.x             | `npm install @ruc-lib/widget@^4.0.0`     |
| 20.x.x             | `npm install @ruc-lib/widget@^4.0.0`     |


## Usage

### 1. Import the Component
In your Angular component file (e.g., `app.component.ts`), import the `RuclibWidgetComponent`:

```typescript
import { Component } from '@angular/core';

// For Complete Library
import { RuclibWidgetComponent } from '@uxpractice/ruc-lib/widget';

// For Individual Package
import { RuclibWidgetComponent } from '@ruc-lib/widget';

@Component({
  selector: 'app-root',
  imports: [RuclibWidgetComponent],
  templateUrl: './app.component.html',
})
export class AppComponent {
  // Component code here
}
```

### 2. Use the Component
In your component's template, use the `<uxp-ruclib-widget>` selector:

```html
<uxp-ruclib-widget
    [rucInputData]="widgetInput"  
    [customTheme]="customTheme"
    (widgetClose)="handleWidgetClose($event)"
    (layoutChanged)="handleLayoutChange($event)">
></uxp-ruclib-widget>
```

## API Reference

### Component Inputs

| Input          | Type                  | Description                                      |
|----------------|-----------------------|--------------------------------------------------|
| `rucInputData` | `WidgetConfig` | The main configuration object for the widgets.   |
| `customTheme`  | `string`              | An optional CSS class for custom theming.        |

### Component Outputs

| Output          | Type               | Description                                                              |
|-----------------|--------------------|--------------------------------------------------------------------------|
| `widgetClose`   | `string`           | Emitted when a widget's close icon is clicked. Returns the widget's `id`.  |
| `layoutChanged` | `WidgetConfigData[]` | Emitted when a widget is moved or resized. Returns the full widget data array. |

### `rucInputData` (`WidgetConfig`)
This object defines the global configuration for the widget container.

| Property     | Type                 | Description                                      |
|--------------|----------------------|--------------------------------------------------|
| `color`      | `string`             | A theme color to apply to the widgets.           |
| `widgetData` | `WidgetConfigData[]` | An array of individual widget configuration objects. |

### `widgetData` Item (`WidgetConfigData`)
This object defines the configuration for each individual widget.

| Property        | Type      | Description                                                                   |
|-----------------|-----------|-------------------------------------------------------------------------------|
| `id`            | `string`  | A unique identifier for the widget.                                           |
| `title`         | `string`  | The title displayed in the widget's header.                                   |
| `description`   | `string`  | A description for the widget, often used for tooltips.                        |
| `contentType`   | `string`  | The type of content to render. Can be `'text'`, `'html'`, or `'component'`.   |
| `contentData`   | `any`     | The data for the content. Can be a string, HTML, or a component reference.    |
| `top`           | `string`  | The initial top position of the widget (e.g., `'20px'`).                      |
| `left`          | `string`  | The initial left position of the widget (e.g., `'20px'`).                     |
| `width`         | `string`  | The initial width of the widget (e.g., `'300px'`).                            |
| `height`        | `string`  | The initial height of the widget (e.g., `'200px'`).                           |
| `draggable`     | `boolean` | If `true`, the widget can be dragged. Default is `true`.                      |
| `showCloseIcon` | `boolean` | If `true`, a close icon is displayed in the header. Default is `true`.        |
| `disabled`      | `boolean` | If `true`, the widget is non-interactive. Default is `false`.                 |
| `headerIcon`    | `string`  | The name of the Material Icon to display in the header.                       |
| `backgroundColor`| `string` | An optional background color for the widget.                                  |

## Example Configuration

Here's an example of how to configure the Widget component in your component's TypeScript file.

```typescript
import { Component } from '@angular/core';

// For Complete Library
import { RuclibWidgetModule, WidgetConfig, WidgetConfigData } from '@uxpractice/ruc-lib/widget';

// For Individual package
import { RuclibWidgetModule, WidgetConfig, WidgetConfigData } from '@ruc-lib/widget';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
  customTheme = 'ruc-custom-theme';

  widgetInput: WidgetConfig = {
    color: 'primary',
    widgetData: [
        {
            id: 'widget-1',
            title: 'Text Widget',
            contentType: 'text',
            contentData: 'This is the default content for the first widget. It is draggable and has a close icon.',
            top: '20px',
            left: '20px',
            width: '300px',
            height: '200px',
            draggable: true,
            showCloseIcon: true,
            headerIcon: 'widgets'
        },
        {
            id: 'widget-2',
            title: 'HTML Widget',
            contentType: 'html',
            contentData: '<h3>HTML Content</h3><p>This widget contains <strong>HTML</strong> and has a different background color.</p>',
            top: '240px',
            left: '20px',
            width: '300px',
            height: '200px',
            draggable: true,
            showCloseIcon: true,
            backgroundColor: '#f0f0f0',
            headerIcon: 'code'
        },
        {
            id: 'widget-3',
            title: 'Disabled Widget',
            contentType: 'text',
            contentData: 'This widget cannot be moved or closed.',
            top: '20px',
            left: '340px',
            width: '300px',
            height: '150px',
            draggable: false,
            showCloseIcon: false,
            disabled: true,
            headerIcon: 'block'
        }
    ]
  };

  handleWidgetClose(widgetId: string) {
    console.log('Widget closed:', widgetId);
    // Logic to remove the widget from the widgetInput.widgetData array
    this.widgetInput.widgetData = this.widgetInput.widgetData.filter(w => w.id !== widgetId);
  }

  handleLayoutChange(widgets: WidgetConfigData[]) {
    console.log('Layout changed:', widgets);
    // Logic to save the new layout configuration
    this.widgetInput.widgetData = widgets;
  }
}
```

> ⚠️ **IMPORTANT: Custom Theme Usage in Angular Material**

When implementing **custom themes**, such as:

```scss
.custom-theme-1 {
  @include angular-material-theme($custom-theme);
}

// You must also include the typography mixin to ensure text styles are applied correctly as shown below:
.custom-theme-1 {
  @include angular-material-theme($custom-theme);
  @include mat.typography-level($theme-custom-typography-name, body-1);
}
```


# Contribution

Contributions are welcome! Feel free to open issues or pull requests for any enhancements or fixes.

# Acknowledgements

Thank you for choosing the Widget Component Library. If you have any feedback or suggestions, please let us know!