0.0.7 • Published 8 months ago

@feedal/embed v0.0.7

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
8 months ago

🚀 Feedal Embed SDK v2.0

A powerful, modern, and flexible JavaScript SDK for embedding Feedal feedback forms across any platform. Built with TypeScript, featuring advanced customization, multiple display modes, framework integration, and excellent developer experience.


✨ Key Features

  • 🎯 Framework Agnostic: Works with React, Angular, Vue, Svelte, and vanilla JavaScript
  • 🎨 Multiple Display Modes: Popup, embedded, fullscreen, drawer, and floating button
  • 🎭 Smart Triggers: Manual, auto, click, scroll, time-based, and element-specific
  • 📱 Fully Responsive: Mobile-first design with adaptive positioning
  • 🎬 Smooth Animations: Fade, slide, scale transitions with customizable timing
  • Accessibility First: ARIA labels, keyboard navigation, screen reader support
  • 🔧 Advanced Configuration: Extensive customization options
  • 📦 Lightweight: ~15KB gzipped, no dependencies
  • 🔒 Secure: Token-based authentication with HMAC support
  • 🌐 Web Components: Native custom elements support

📦 Installation

CDN (Recommended for quick setup)

<script src="https://cdn.jsdelivr.net/npm/@feedal/embed@latest/dist/embed.umd.js"></script>

NPM/Yarn (Recommended for applications)

npm install @feedal/embed
# or
yarn add @feedal/embed

🚀 Quick Start

Simple Popup Form

<script src="https://cdn.jsdelivr.net/npm/@feedal/embed@latest/dist/embed.umd.js"></script>
<script>
  const widget = FeedalForm.createWidget({
    formId: 'your-form-id',
    token: 'your-auth-token',
    mode: 'popup'
  });
  
  widget.open();
</script>

Auto-trigger with Script Tag

<script 
  src="https://cdn.jsdelivr.net/npm/@feedal/embed@latest/dist/embed.umd.js"
  data-form-id="your-form-id"
  data-token="your-auth-token"
  data-mode="popup"
  data-trigger="time"
  data-trigger-delay="5000"
  data-position="bottom-right"
  data-animation="slide">
</script>

🎛️ Complete Configuration Options

interface EmbedOptions {
  // Core Configuration
  formId: string;                   // Required: Your form ID
  token?: string;                   // Authentication token
  host?: string;                    // API host (defaults to production)

  // Display & Layout
  mode?: 'fullscreen' | 'embedded' | 'popup' | 'drawer' | 'button';
  theme?: 'light' | 'dark' | 'auto' | 'custom';
  customCssUrl?: string;            // Custom CSS file URL
  
  // Positioning & Sizing  
  width?: string | number;          // Default: '400px'
  height?: string | number;         // Default: '600px'
  position?: 'top-left' | 'top-center' | 'top-right' | 
             'bottom-left' | 'bottom-center' | 'bottom-right' | 'center';
  offset?: { x?: number; y?: number }; // Fine-tune positioning
  
  // Behavior
  trigger?: 'manual' | 'auto' | 'click' | 'scroll' | 'time';
  triggerDelay?: number;            // Delay for time/auto triggers
  triggerElement?: string | HTMLElement; // Target element for click trigger
  autoClose?: boolean | number;     // Auto-close after submission
  closeOnOverlayClick?: boolean;    // Close when clicking outside
  showCloseButton?: boolean;        // Show/hide close button
  
  // Responsive & Accessibility
  responsive?: boolean;             // Enable responsive behavior
  maxWidth?: string | number;       // Maximum width constraint
  minWidth?: string | number;       // Minimum width constraint
  zIndex?: number;                  // Custom z-index
  ariaLabel?: string;              // Accessibility label
  
  // Advanced Features
  containerId?: string;            // Container for embedded mode
  animation?: 'fade' | 'slide' | 'scale' | 'none';
  overlay?: boolean;               // Show background overlay
  
  // Data & Context
  metadata?: Record<string, any>;  // Additional context data
  prefill?: Record<string, any>;   // Prefill form fields
  
  // Event Callbacks
  onLoad?: () => void;             // Form loaded and ready
  onOpen?: () => void;             // Form opened/shown
  onClose?: () => void;            // Form closed/hidden
  onSubmit?: (data?: any) => void; // Form submitted
  onError?: (error: Error) => void; // Error occurred
}

🎮 Display Modes

1. Popup Mode (Default)

Displays form in a centered modal overlay.

FeedalForm.createWidget({
  formId: 'abc123',
  mode: 'popup',
  position: 'center',
  width: 500,
  height: 700,
  overlay: true,
  animation: 'fade'
});

2. Embedded Mode

Embeds form inside a specific container.

<div id="feedback-container"></div>
<script>
  FeedalForm.createWidget({
    formId: 'abc123',
    mode: 'embedded',
    containerId: 'feedback-container',
    width: '100%',
    height: 600
  });
</script>

3. Drawer Mode

Slides in from the side of the screen.

FeedalForm.createWidget({
  formId: 'abc123',
  mode: 'drawer',
  position: 'bottom-right',
  width: 400,
  animation: 'slide'
});

4. Floating Button

Shows a floating button that expands to form.

FeedalForm.createWidget({
  formId: 'abc123',
  mode: 'button',
  position: 'bottom-right',
  trigger: 'manual'
});

🎯 Smart Triggers

Manual Trigger

const widget = FeedalForm.createWidget({
  formId: 'abc123',
  trigger: 'manual'
});

// Open programmatically
widget.open();

Time-based Trigger

FeedalForm.createWidget({
  formId: 'abc123',
  trigger: 'time',
  triggerDelay: 10000 // 10 seconds
});

Scroll Trigger

FeedalForm.createWidget({
  formId: 'abc123',
  trigger: 'scroll',
  triggerDelay: 75 // Trigger at 75% scroll
});

Click Trigger

FeedalForm.createWidget({
  formId: 'abc123',
  trigger: 'click',
  triggerElement: '#feedback-button' // CSS selector or HTML element
});

🌐 Framework Integration

React

import { FeedalWidget, EmbedOptions } from '@feedal/embed';
import { useEffect, useState } from 'react';

function FeedbackForm({ formId, ...options }: EmbedOptions) {
  const [widget, setWidget] = useState<FeedalWidget | null>(null);

  useEffect(() => {
    const feedalWidget = new FeedalWidget({
      formId,
      ...options,
      onSubmit: (data) => {
        console.log('Form submitted:', data);
      }
    });

    setWidget(feedalWidget);
    return () => feedalWidget.destroy();
  }, [formId]);

  return (
    <button onClick={() => widget?.open()}>
      Give Feedback
    </button>
  );
}

Vue 3

<template>
  <button @click="widget?.open()">Give Feedback</button>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { FeedalWidget, EmbedOptions } from '@feedal/embed';

interface Props extends EmbedOptions {
  formId: string;
}

const props = defineProps<Props>();
const widget = ref<FeedalWidget | null>(null);

onMounted(() => {
  widget.value = new FeedalWidget(props);
});

onUnmounted(() => {
  widget.value?.destroy();
});
</script>

Angular

import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { FeedalWidget, EmbedOptions } from '@feedal/embed';

@Component({
  selector: 'app-feedback',
  template: `<button (click)="openFeedback()">Give Feedback</button>`
})
export class FeedbackComponent implements OnInit, OnDestroy {
  @Input() formId!: string;
  @Input() options: Partial<EmbedOptions> = {};
  
  private widget?: FeedalWidget;

  ngOnInit() {
    this.widget = new FeedalWidget({
      formId: this.formId,
      ...this.options
    });
  }

  ngOnDestroy() {
    this.widget?.destroy();
  }

  openFeedback() {
    this.widget?.open();
  }
}

Web Components

<feedal-form 
  form-id="abc123"
  token="your-token"
  mode="popup"
  theme="dark"
  auto-close="true">
</feedal-form>

<script>
  const form = document.querySelector('feedal-form');
  form.addEventListener('submit', (event) => {
    console.log('Form submitted:', event.detail);
  });
</script>

🎨 Advanced Customization

Custom Themes

FeedalForm.createWidget({
  formId: 'abc123',
  theme: 'custom',
  customCssUrl: 'https://yoursite.com/feedal-theme.css'
});

Custom CSS Variables

:root {
  --feedal-primary-color: #6366f1;
  --feedal-background: #ffffff;
  --feedal-text-color: #374151;
  --feedal-border-radius: 12px;
  --feedal-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}

Dynamic Configuration

const widget = FeedalForm.createWidget({
  formId: 'abc123',
  mode: 'popup'
});

// Update configuration dynamically
widget.updateOptions({
  theme: 'dark',
  position: 'bottom-right',
  width: 600
});

📱 Responsive Design

The SDK automatically adapts to different screen sizes:

  • Desktop: Full-sized popups and drawers
  • Tablet: Responsive sizing with max-width constraints
  • Mobile: Full-width modals with optimized positioning
FeedalForm.createWidget({
  formId: 'abc123',
  responsive: true,
  width: 500,
  maxWidth: '90vw', // Ensures mobile compatibility
  minWidth: 320
});

🔐 Authentication & Security

JWT Tokens

FeedalForm.createWidget({
  formId: 'abc123',
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  metadata: {
    userId: '12345',
    userEmail: 'user@example.com'
  }
});

HMAC Signatures

const signature = generateHMACSignature(formId, timestamp, secretKey);

FeedalForm.createWidget({
  formId: 'abc123',
  token: signature,
  metadata: { timestamp }
});

📊 Event Handling & Analytics

const widget = FeedalForm.createWidget({
  formId: 'abc123',
  onLoad: () => {
    console.log('Form loaded');
    analytics.track('Feedback Form Loaded');
  },
  onOpen: () => {
    console.log('Form opened');
    analytics.track('Feedback Form Opened');
  },
  onSubmit: (data) => {
    console.log('Form submitted:', data);
    analytics.track('Feedback Submitted', data);
  },
  onClose: () => {
    console.log('Form closed');
    analytics.track('Feedback Form Closed');
  },
  onError: (error) => {
    console.error('Form error:', error);
    analytics.track('Feedback Form Error', { error: error.message });
  }
});

🛠️ Advanced API

Widget Management

// Create multiple widgets
const feedbackWidget = FeedalForm.createWidget({ formId: 'feedback-123' });
const surveyWidget = FeedalForm.createWidget({ formId: 'survey-456' });

// Access widgets by ID
const widget = FeedalForm.getInstance('feedback-123');

// Destroy specific widget
widget.destroy();

// Destroy all widgets
FeedalForm.destroyAll();

// Check if any widget is open
if (FeedalForm.isFormOpen()) {
  console.log('A form is currently open');
}

Programmatic Control

const widget = FeedalForm.createWidget({
  formId: 'abc123',
  trigger: 'manual'
});

// Open/close/toggle
widget.open();
widget.close(); 
widget.toggle();

// Check state
console.log(widget.isVisible); // boolean
console.log(widget.element);   // HTMLElement | null

// Update options
widget.updateOptions({
  theme: 'dark',
  position: 'top-right'
});

🔧 Migration Guide

From v1.x to v2.x

// Old API (v1.x) - Still supported
openForm('abc123', {
  theme: 'dark',
  mode: 'popup'
});

// New API (v2.x) - Recommended
const widget = FeedalForm.createWidget({
  formId: 'abc123',
  theme: 'dark', 
  mode: 'popup'
});
widget.open();

Breaking Changes

  • popover mode renamed to popup
  • popoverPosition renamed to position
  • customCssUrl replaces individual CSS parameters
  • Enhanced TypeScript definitions

🐛 Troubleshooting

Common Issues

Form not loading:

// Check console for errors
widget.onError = (error) => console.error(error);

// Verify form ID and token
console.log('Form ID:', widget.options.formId);

Styling conflicts:

/* Isolate Feedal styles */
#feedal-widget-abc123 {
  all: initial;
}

Mobile issues:

// Enable responsive mode
FeedalForm.createWidget({
  formId: 'abc123',
  responsive: true,
  width: '90vw',
  maxWidth: 500
});

📈 Performance Tips

  1. Lazy Loading: Load the SDK only when needed
  2. Preload: Use <link rel="preload"> for critical forms
  3. Caching: Enable CDN caching for better performance
  4. Minimize: Use production builds in production
// Lazy load example
async function loadFeedbackForm() {
  if (!window.FeedalForm) {
    await import('@feedal/embed');
  }
  
  return FeedalForm.createWidget({
    formId: 'abc123'
  });
}

🆘 Support & Resources


📄 License

This project is licensed under the MIT License.


Made with ❤️ by the Feedal Team

0.0.7

8 months ago

0.0.6

8 months ago

0.0.5

8 months ago

0.0.4

8 months ago

0.0.3

8 months ago

0.0.2

8 months ago

0.0.1

8 months ago