npm package: @iviva/widget-overlay
Description: A flexible and extensible overlay system designed for building **Digital Twin** interfaces using **UXP widgets**. This library provides a set of components, utilities, and configuration models to integrate a digital twin viewer with layout management, too
Author: dinesh-gamage
Latest version: 0.0.9

# @iviva/widget-overlay

A flexible and extensible overlay system designed for building **Digital Twin** interfaces using **UXP widgets**. This library provides a set of components, utilities, and configuration models to integrate a digital twin viewer with layout management, toolbar controls, and event-based data loading.

---

## ✨ Features

* `WidgetOverlay` component to configure and display widgets over any digital twin provider.
* Support for **multiple providers** with customizable configuration panels.
* Configure and manage layouts for different **viewports (screen sizes)**.
* Built-in **viewport simulator** for layout testing and editing.
* Use UXP's **widget drawer** to dynamically add widgets.
* Utility components to support toolbar creation and layout tools.
* **Event-based communication** between overlay and provider.
* Integrated, customizable **information panel**.
* Utility class `GlassEffectClassName` to apply glass effect styling.

---

## 🚀 Getting Started

### Installation

```bash
npm install @iviva/widget-overlay
```

---

## 📦 Basic Usage

```tsx
import { WidgetOverlay } from '@iviva/widget-overlay';

const BasicExample = ({ uxpContext }) => {
  return (
    <div className="my-digital-twin">
      <WidgetOverlay
        uxpContext={uxpContext}
        digitalTwinProviders={digitalTwinProviders}
      >
        <YourDigitalTwinComponent />
      </WidgetOverlay>
    </div>
  );
};
```

---

## 🧠 How It Works

`WidgetOverlay` is the main component that integrates your digital twin viewer with UXP widgets.

* Uses **Lucy's DigitalTwinConfigurationsModel** to persist configuration data.
* You can also bring your own model/actions for custom data handling.
* Layouts are identified by a combination of:

  * **Viewport** (e.g., `1024x768`)
  * **Layout ID** (e.g., `home`, `floor`, `asset`)

### Event Workflow

1. On load, the overlay listens for a **status event** (default: `dt-viewer-status-event`).

   * When received with `{ isReady: true }`, it fetches data and determines layout.
2. The viewer can send a **navigation event** (default: `dt-view-change-event`) with objectType and objectId.

   * Based on the payload, the correct layout and widgets are rendered.

---

## ⚙️ Configuration Options

| Prop                        | Type                           | Default                    | Description                              |                                |
| --------------------------- | ------------------------------ | -------------------------- | ---------------------------------------- | ------------------------------ |
| `uxpContext`                | `IContextProvider`             | —                          | UXP context object                       |                                |
| `digitalTwinProviders`      | `DigitalTwinProvider[]`        | —                          | List of providers with configuration UIs |                                |
| `initialLayoutId`           | `string`                       | `'home'`                   | Initial layout ID                        |                                |
| `viewerStatusEventName`     | `string`                       | `'dt-viewer-status-event'` | Event ID to listen for viewer readiness  |                                |
| `viewerNavigationEventName` | `string`                       | `'dt-view-change-event'`   | Event ID for view changes                |                                |
| `onToggleEdit`              | `(isEditing: boolean) => void` | —                          | Callback when edit mode toggles          |                                |
| `onViewportChange`          | \`(viewport: string            | null) => void\`            | —                                        | Callback when viewport changes |
| `informationPanel`          | `object`                       | `{}`                       | Show/hide info panel with extra details  |                                |
| `configurations`            | `object`                       | —                          | Access control and custom tabs           |                                |
| `customToolbarItems`        | `ToolbarButton[]`              | `[]`                       | Add buttons to the toolbar               |                                |
| `numberOfCells`             | `number`                       | `30`                       | Grid density                             |                                |
| `overlayBackground`         | `string`                       | radial gradient            | Grid overlay background                  |                                |
| `showGridWhenEditing`       | `boolean`                      | `false`                    | Show layout grid while editing           |                                |

### Type Definitions

```ts
export interface DigitalTwinProvider {
    id: string;
    name: string;
    renderConfigurations: (exitEditMode: () => void) => ReactNode;
}

export interface ViewerStatusPayload {
    isReady: boolean;
}

export interface ViewerNavigationPayload {
    objectId: string;
    objectType: string;
    additionalData?: Record<string, any>;
}

export interface OverlayConfigurations {
    overlayBackground: string;
    numberOfCells: number;
    padding: number;
    margin: number;
}
```

---

## 🎯 Triggering Events

### Viewer Ready Event

This signals the overlay that the viewer is ready.

```ts
import { eventDispatcher } from 'uxp/components';
import { DefaultViewerStatusEventName } from '@iviva/widget-overlay';

eventDispatcher('your-app', DefaultViewerStatusEventName, { isReady: true });
```

### View Change Event

This tells the overlay that navigation occurred. Example:

```ts
import { eventDispatcher } from 'uxp/components';
import { DefaultViewerNavigationEventName } from '@iviva/widget-overlay';

const payload = {
  objectId: 'stall-001',
  objectType: 'stalls',
  additionalData: { locationId: 24 }
};

eventDispatcher('your-app', DefaultViewerNavigationEventName, payload);
```

---

## 🧪 Full Example

```tsx
import React, { useState, useEffect } from 'react';
import { WidgetOverlay, Section, getDigitalTwinConfigurations, saveDigitalTwinConfigurations, DefaultViewerStatusEventName, DefaultViewerNavigationEventName } from '@iviva/widget-overlay';
import { Button, Input, eventDispatcher } from 'uxp/components';

const DummyProvider = {
  id: 'dummy',
  name: 'Dummy Twin',
  renderConfigurations: (exitEditMode) => {
    const [apiKey, setApiKey] = useState('');

    return (
      <>
        <Section label='API Key'>
          <Input value={apiKey} onChange={(v) => setApiKey(v)} />
        </Section>
        <Button title='Save' onClick={() => {
          saveDigitalTwinConfigurations(uxpContext, { apiKey }).then(() => {
            exitEditMode();
          });
        }} />
      </>
    );
  }
};

export function triggerViewerReadyEvent() {
  eventDispatcher('my-dt-app', DefaultViewerStatusEventName, { isReady: true });
}

export function triggerViewChangeEvent(payload) {
  eventDispatcher('my-dt-app', DefaultViewerNavigationEventName, payload);
}

const MyDigitalTwin = ({ uxpContext }) => {
  const [config, setConfig] = useState({ apiKey: '' });

  useEffect(() => {
    getDigitalTwinConfigurations(uxpContext).then(({ data }) => setConfig(data || { apiKey: '' }));
    triggerViewerReadyEvent();
  }, [uxpContext]);

  return (
    <WidgetOverlay
      uxpContext={uxpContext}
      digitalTwinProviders={[DummyProvider]}
      showGridWhenEditing
      configurations={{ allowedToConfigure: { userRoles: [], userGroups: [] } }}
      informationPanel={{ show: true }}
    >
      <div>Render your twin here</div>
    </WidgetOverlay>
  );
};
```

---

## 🔒 Restrictions & Best Practices

* Build widgets **separately** from the Digital Twin application that uses `WidgetOverlay`.
* Widgets should accept the following props for compatibility:

```ts
interface DigitalTwinWidgetOverlayWidgetProps {
  uxpContext: IContextProvider;
  instanceId?: string;
  objectId?: string;
  objectType?: string;
  additionalData?: Record<string, any>;
}
```

This ensures your widgets receive necessary context and can adapt to view changes.

---

## 📚 API Reference

### 🔧 Components

* `WidgetOverlay`
* `ToolbarIconButton`, `ToolbarInput`, `ToolbarSelectInput`
* `Section`, `Separator`

### ⚙️ Utilities

* `getDigitalTwinConfigurations(uxpContext)`
* `saveDigitalTwinConfigurations(uxpContext, config)`
* `getDigitalTwinProvider()`
* `setDigitalTwinProvider(provider)`
* `getCurrentViewport()`

### 🔁 Constants

* `DefaultViewerStatusEventName`
* `DefaultViewerNavigationEventName`
* `GlassEffectClassName`

---

## 🛠 Styling

This package includes embedded styles. You can override them using your own CSS selectors if needed.

To apply the glass effect, use the class:

```html
<div className="ivivadtwl_glasseffect">...</div>
```

---

## 📥 Contributing

We welcome issues, suggestions, and pull requests. Please follow standard code conventions.

---

## 📄 License

MIT © [iviva](https://www.iviva.com)