<p align="center">
  <a href="https://myop.dev">
    <img src="https://docs.myop.dev/img/logo.svg" alt="Myop Logo" width="200" />
  </a>
</p>

<h1 align="center">Myop SDK</h1>

<p align="center">
  <strong>Dynamic UI component management for modern web applications</strong>
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/@myop/sdk"><img src="https://img.shields.io/npm/v/@myop/sdk.svg?style=flat-square" alt="npm version" /></a>
  <a href="https://www.npmjs.com/package/@myop/sdk"><img src="https://img.shields.io/npm/dm/@myop/sdk.svg?style=flat-square" alt="npm downloads" /></a>
  <a href="https://myop.dev/discord"><img src="https://img.shields.io/badge/Discord-Join%20Us-7289da?style=flat-square&logo=discord&logoColor=white" alt="Discord" /></a>
</p>

<p align="center">
  <a href="https://docs.myop.dev">Documentation</a> |
  <a href="https://myop.dev">Website</a> |
  <a href="https://myop.dev/discord">Discord</a>
</p>

---

## What is Myop?

Myop is an open-source SDK that enables **real-time UI modifications without deployments**. It bridges your application logic with dynamically swappable user interfaces, allowing developers to:

- Experiment with UI/UX changes instantly
- Refactor component appearance without touching core functionality
- Maintain typed communication between components and host applications
- Load and manage UI components dynamically at runtime

## Installation

```bash
npm install @myop/sdk
```

Or via CDN:

```html
<script src="https://cdn.myop.dev/sdk/next/myop_sdk.min.js"></script>
```

## Quick Start

### Using npm/ESM

```typescript
import { getHostModule } from '@myop/sdk';

// Initialize the SDK
const { hostSDK } = await getHostModule();
hostSDK.init();

// Load a component
const component = await hostSDK.loadComponent(componentConfig, containerElement);
await component.initiated();
```

### Using CDN

```html
<script src="https://cdn.myop.dev/sdk/next/myop_sdk.min.js"></script>
<script>
  const { hostSDK } = await window.myop.rootSDK.getHostModule();
  hostSDK.init();

  const component = await hostSDK.loadComponent(config, document.getElementById('app'));
  await component.initiated();
</script>
```

## Architecture

The Myop SDK is modular, consisting of several specialized packages:

| Module | Description | Import |
|--------|-------------|--------|
| **Host SDK** | Core module for embedding and managing Myop components | `@myop/sdk` or `@myop/sdk/host` |
| **Iframe SDK** | Secure isolation for components in iframes | `@myop/sdk/iframe` |
| **WebComponent SDK** | Support for self-contained web components | `@myop/sdk/webcomponent` |
| **Messages** | Type-safe communication between host and components | `@myop/sdk/messages` |
| **Helpers** | Utility functions and configuration builders | `@myop/sdk/helpers` |

## Framework Integration

Myop provides official framework packages for seamless integration:

| Package | Install |
|---------|---------|
| React | `npm install @myop/react` |
| Vue.js | `npm install @myop/vue` |
| Angular | `npm install @myop/angular` |

<details>
<summary><strong>React</strong></summary>

```bash
npm install @myop/react
```

```tsx
import { MyopComponent } from '@myop/react';

function App() {
  return (
    <MyopComponent
      componentId="your-component-id"
      environment="production"
      data={{ user: 'John' }}
      onLoad={(component) => console.log('Component loaded', component)}
      onError={(error) => console.error('Error:', error)}
      on={(action, payload) => {
        // Handle CTA actions from the component
        console.log('Action:', action, payload);
      }}
      loader={<div>Loading...</div>}
      fallback={<div>Failed to load</div>}
    />
  );
}
```

**Props:**

| Prop | Type | Description |
|------|------|-------------|
| `componentId` | `string` | Component ID from Myop Cloud |
| `environment` | `string` | Environment identifier (default: `"production"`) |
| `data` | `any` | Data passed to `myop_init_interface` |
| `onLoad` | `(component) => void` | Called when component loads |
| `onError` | `(error) => void` | Called on error |
| `on` | `(action, payload) => void` | Handler for `myop_cta_handler` calls |
| `loader` | `ReactNode` | Custom loading indicator |
| `fallback` | `ReactNode` | Custom error fallback |
| `fadeDuration` | `number` | Loader fade duration in ms |

**Preloading:**

```tsx
import { preload, isPreloaded } from '@myop/react';

// Preload components for faster rendering
await preload(['component-1', 'component-2'], 'production');

// Check if already loaded
if (isPreloaded('component-1')) {
  // Component will render instantly
}
```

**Local Development:**

```tsx
import { enableLocalDev } from '@myop/react';

// Point to local server
enableLocalDev();
```

</details>

<details>
<summary><strong>Vue.js</strong></summary>

```bash
npm install @myop/vue
```

```vue
<template>
  <MyopContainer
    :componentId="componentId"
    :flowId="flowId"
    @ready="onReady"
    v-bind="$attrs"
  >
    <template #loading>
      <div>Loading...</div>
    </template>
  </MyopContainer>
</template>

<script setup lang="ts">
import { MyopContainer } from '@myop/vue';
import type { IMyopComponent } from '@myop/sdk/host';

const componentId = 'your-component-id';
const flowId = 'optional-flow-id';

const onReady = (component: IMyopComponent, innerRef?: any) => {
  console.log('Component loaded', component);
};
</script>
```

**Props:**

| Prop | Type | Description |
|------|------|-------------|
| `componentId` | `string` | Component ID from Myop Cloud |
| `flowId` | `string?` | Optional flow ID |
| `onReady` | `(component, innerRef?) => void` | Called when component loads |

**Slots:**

| Slot | Description |
|------|-------------|
| `loading` | Shown while component loads |

</details>

<details>
<summary><strong>Angular</strong></summary>

```bash
npm install @myop/angular
```

```typescript
import { Component } from '@angular/core';
import { MyopContainerComponent } from '@myop/angular';
import type { IMyopComponent } from '@myop/sdk/host';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [MyopContainerComponent],
  template: `
    <myop-container
      [componentId]="componentId"
      [flowId]="flowId"
      [inputs]="inputs"
      (componentReady)="onComponentReady($event)"
    >
      <!-- Content shown while loading -->
      <div>Loading...</div>
    </myop-container>
  `
})
export class AppComponent {
  componentId = 'your-component-id';
  flowId?: string;
  inputs = { theme: 'dark' };

  onComponentReady(component: IMyopComponent) {
    console.log('Component loaded', component);
  }
}
```

**Inputs:**

| Input | Type | Description |
|-------|------|-------------|
| `componentId` | `string` | Component ID from Myop Cloud |
| `flowId` | `string?` | Optional flow ID |
| `inputs` | `object` | Data passed to the component |

**Outputs:**

| Output | Type | Description |
|--------|------|-------------|
| `componentReady` | `IMyopComponent` | Emitted when component loads |

</details>

<details>
<summary><strong>Vanilla JavaScript / CDN</strong></summary>

```html
<div id="myop-container"></div>

<script src="https://cdn.myop.dev/sdk/next/myop_sdk.min.js"></script>
<script>
  async function init() {
    const { hostSDK } = await window.myop.rootSDK.getHostModule();
    const { CloudRepository } = await window.myop.rootSDK.getMyopHelpers();

    const container = document.getElementById('myop-container');

    // ============ V1: User Flows ============
    // Fetch from auto-generated flow
    const configV1 = await CloudRepository.Main.fetchComponentV1('component-id');
    await hostSDK.loadComponent(configV1, container);

    // Or fetch from a specific flow
    const configFromFlow = await CloudRepository.Main.fetchComponentV1('component-id', 'flow-id');

    // ============ V2: Direct Variant Loading ============
    // Fetch variant directly by component ID and environment
    const variantV2 = await CloudRepository.Main.fetchComponentV2('component-id', 'production');
    await hostSDK.loadComponent(variantV2, container);
  }

  init();
</script>
```

</details>

## API Reference

### CloudRepository

Fetch component configurations from Myop Cloud:

```typescript
import { CloudRepository } from '@myop/sdk/helpers';

// Fetch a component (v1 - from user flows)
const componentConfig = await CloudRepository.Main.fetchComponent('component-id');

// Fetch a component from a specific flow
const componentConfig = await CloudRepository.Main.fetchComponent('component-id', 'flow-id');

// Fetch a v2 component variant
const variantConfig = await CloudRepository.Main.fetchComponentV2('component-id', 'environment');

// Fetch a complete user flow
const flow = await CloudRepository.Main.fetchFlow('flow-id');

// Check if a component is preloaded
const isLoaded = CloudRepository.Main.isPreloaded('component-id');
```

### Host SDK

```typescript
import { getHostModule } from '@myop/sdk';

const { hostSDK } = await getHostModule();

// Load a component into a container
const component = await hostSDK.loadComponent(componentConfig, containerElement);

// Load with options
const component = await hostSDK.loadComponent(componentConfig, container, {
  hidden: false,           // Start hidden
  connectProps: true,      // Auto-connect props (default: true)
  timeout: 5000,           // Initialization timeout
  hooks: {                 // Lifecycle hooks
    afterSkinSelected: async (skin) => skin
  }
});

// Navigate to a different component
const newComponent = await hostSDK.navigate(currentComponent, newConfig, {
  staged: true,  // Load new component before disposing old one
});

// Send messages to component
component.send(message);

// Dispose component
component.dispose();
```

### ComponentConfig Builder

Build component configurations programmatically:

```typescript
import { ComponentConfig, SkinConfig } from '@myop/sdk/helpers';

const skin = SkinConfig.create()
  .withHTMLLoader({
    HTML: '<div>My Component</div>',
    shadowRootMode: 'open'
  })
  .build();

const config = ComponentConfig.create()
  .withName('my-component')
  .withDefaultSkin(skin)
  .withBasicRef('header')
  .withBasicRef('content')
  .build();
```

### Iframe SDK

For components running inside iframes:

```typescript
import { getIframeModule } from '@myop/sdk';

const { IframeSDK } = await getIframeModule();
```

### WebComponent SDK

For self-contained web components:

```typescript
import { getWebcomponentModule } from '@myop/sdk';

const { WebComponentSDK } = await getWebcomponentModule();
```

## Documentation

For comprehensive documentation, guides, and examples, visit **[docs.myop.dev](https://docs.myop.dev)**.

- [Getting Started Guide](https://docs.myop.dev/docs/quickstart)
- [SDK Reference](https://docs.myop.dev/docs/sdk)
- [Auto-Generated Packages](https://docs.myop.dev/docs/learnMyop/AutoGeneratedPackages)

## Related Resources

- [Read more about Myop](https://myop.dev)
- [Myop Documentation](https://docs.myop.dev)
- [Discord Community](https://myop.dev/discord)

## License

This project is licensed under the [MIT License](LICENSE).

---

<p align="center">
  Made with care by the <a href="https://myop.dev">Myop</a> team
</p>
