npm package: @knitknot-ai/widget
Description: Official NPM package for embedding KnitKnot release notes into customer applications
Author: KnitKnot
Latest version: 1.5.1
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

# @knitknot-ai/widget

Official NPM package for embedding KnitKnot release notes into customer applications. A lightweight (~3KB) JavaScript SDK that displays your release notes in a beautiful, customizable widget.

## Overview

The KnitKnot widget allows you to embed your release notes directly into your application with just a workspace ID. The widget loads in an isolated iframe from `widget.knitknot.ai`, ensuring zero conflicts with your styles or scripts.

### Key Features

- 🚀 **Lightweight** - Only ~3KB minified
- 🔒 **Fully Isolated** - Runs in iframe, no CSS/JS conflicts  
- 🎨 **Customizable** - Matches your brand automatically
- 📱 **Responsive** - Works on all devices
- 🔧 **Framework Agnostic** - React, Vue, Angular, or vanilla JS
- 📝 **TypeScript Support** - Full type definitions included
- ⚡ **Non-blocking** - Instant open/close, no loading delays
- 🤝 **Good Citizen** - No CSS injection, no resource hogging

## Installation

```bash
npm install @knitknot-ai/widget
# or
yarn add @knitknot-ai/widget
# or
pnpm add @knitknot-ai/widget
```

## Quick Start

### React Hook (Recommended)

```jsx
import { useKnitKnot } from '@knitknot-ai/widget';

function App() {
  const { open } = useKnitKnot('your-workspace-id');
  
  return (
    <button onClick={open}>
      What's New
    </button>
  );
}
```

### With React Provider

```jsx
import { KnitKnotProvider } from '@knitknot-ai/widget';

// In your root component
function App() {
  return (
    <KnitKnotProvider workspaceId="your-workspace-id">
      <YourApp />
    </KnitKnotProvider>
  );
}

// In any child component
import { useKnitKnot } from '@knitknot-ai/widget';

function Header() {
  const { open, isOpen } = useKnitKnot();
  
  return (
    <button onClick={open}>
      {isOpen ? 'Close' : 'What\'s New'}
    </button>
  );
}
```

### Vanilla JavaScript

```html
<script type="module">
  import { useKnitKnot } from '@knitknot-ai/widget';
  
  const widget = useKnitKnot('your-workspace-id');
  
  document.getElementById('whats-new-btn').addEventListener('click', () => {
    widget.open();
  });
</script>
```

## API Reference

### `useKnitKnot(workspaceIdOrConfig)`

The main hook for using KnitKnot.

```typescript
const {
  open,      // Function to open the widget (instant, non-blocking)
  close,     // Function to close the widget  
  toggle,    // Function to toggle open/closed
  isOpen,    // Boolean indicating if widget is open
  identify,  // Function to identify the current user
  isLoading  // Boolean indicating if widget is still loading
} = useKnitKnot('workspace-id');
```

#### Parameters

- `workspaceIdOrConfig` - Your workspace ID (string) or a config object:

```typescript
interface KnitKnotConfig {
  workspaceId: string;  // Required: Your workspace ID
  zIndex?: number;      // Optional: Widget z-index (default: 99999)
}
```

### User Identification

Track which users have seen which releases:

```jsx
const { identify } = useKnitKnot('workspace-id');

// Identify your user
identify({
  userId: 'user-123',
  email: 'user@example.com',
  company: 'Acme Inc',
  plan: 'pro',
  // Add any custom properties
  customProperty: 'value'
});
```

## Integration Examples

### Next.js App Router

```tsx
// app/providers.tsx
'use client';
import { KnitKnotProvider } from '@knitknot-ai/widget';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <KnitKnotProvider workspaceId="your-workspace-id">
      {children}
    </KnitKnotProvider>
  );
}

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

### Vue 3

```javascript
// main.js
import { createApp } from 'vue';
import { useKnitKnot } from '@knitknot-ai/widget';

const app = createApp(App);

app.config.globalProperties.$knitknot = useKnitKnot('your-workspace-id');
app.mount('#app');

// In component
export default {
  methods: {
    showReleaseNotes() {
      this.$knitknot.open();
    }
  }
}
```

### Angular

```typescript
// app.service.ts
import { Injectable } from '@angular/core';
import { useKnitKnot } from '@knitknot-ai/widget';

@Injectable({ providedIn: 'root' })
export class KnitKnotService {
  private widget = useKnitKnot('your-workspace-id');
  
  open() {
    this.widget.open();
  }
  
  close() {
    this.widget.close();
  }
}
```

## Advanced Patterns

### Render Props

```jsx
import { KnitKnot } from '@knitknot-ai/widget';

<KnitKnot workspaceId="your-workspace-id">
  {({ open, isOpen }) => (
    <CustomButton onClick={open} active={isOpen}>
      Release Notes
    </CustomButton>
  )}
</KnitKnot>
```

### Higher-Order Component

```jsx
import { withKnitKnot } from '@knitknot-ai/widget';

const MyComponent = ({ openReleaseNotes, releaseNotesOpen }) => (
  <button onClick={openReleaseNotes}>
    {releaseNotesOpen ? 'Close' : 'What\'s New'}
  </button>
);

export default withKnitKnot(MyComponent, 'your-workspace-id');
```

## How It Works

1. **Widget Creation**: When initialized, the package prepares a container (no network calls)
2. **On-Demand Loading**: Iframe is created only when `open()` is first called
3. **Instant Feedback**: Container shows immediately, iframe loads in background
4. **Smart Reuse**: Iframe is reused between opens/closes (no recreation overhead)
5. **Communication**: Uses `postMessage` API for secure cross-origin communication

### Architecture

```
Your App → @knitknot-ai/widget → iframe → widget.knitknot.ai → KnitKnot API
           (3KB npm package)              (Handles everything)
```

The NPM package is intentionally minimal - it only handles:
- Creating and positioning the iframe (on-demand)
- Managing open/close state (instant, non-blocking)
- Forwarding user identification
- Listening for widget events

All the heavy lifting (data fetching, rendering, styling) happens in the iframe, which means:
- ✅ Updates without requiring package updates
- ✅ No impact on your bundle size
- ✅ Complete style isolation
- ✅ Automatic feature updates

### Performance Philosophy

This library is designed to be a "good citizen" in your application:

**What we do:**
- Show/hide instantly without delays
- Reuse iframe between opens (no recreation)
- Emit events for state changes
- Warn on slow loads (3s timeout)

**What we DON'T do:**
- ❌ No CSS injection into your page
- ❌ No loading spinners or overlays
- ❌ No animations or transitions
- ❌ No prefetching or preconnecting
- ❌ No blocking operations
- ❌ No resource hogging

## TypeScript Support

Full TypeScript definitions included:

```typescript
import { 
  useKnitKnot, 
  KnitKnotConfig,
  KnitKnotContextValue,
  User,
  WidgetInstance 
} from '@knitknot-ai/widget';
```

## Finding Your Workspace ID

1. Log into [KnitKnot Dashboard](https://app.knitknot.ai)
2. Navigate to Settings → Widget
3. Copy your workspace ID
4. That's it! No API keys needed

## Browser Support

- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Mobile browsers

## Security

- **Read-only**: Widget only displays data, no write operations
- **Sandboxed**: Runs in isolated iframe with restricted permissions
- **HTTPS Only**: Widget always loads over secure connection
- **No Cookies**: Uses postMessage API for communication

## Development

```bash
# Install dependencies
npm install

# Run tests
npm test

# Build package
npm run build

# Lint code
npm run lint
```

## License

MIT - see [LICENSE](LICENSE) file for details

## Support

- **Documentation**: [docs.knitknot.ai](https://docs.knitknot.ai)
- **Issues**: [github.com/knitknot/widget/issues](https://github.com/knitknot/widget/issues)
- **Email**: support@knitknot.ai