0.0.7 • Published 11 months ago

@feedal/embed v0.0.7

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
11 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

11 months ago

0.0.6

11 months ago

0.0.5

11 months ago

0.0.4

11 months ago

0.0.3

11 months ago

0.0.2

11 months ago

0.0.1

11 months ago