Universal Usage

Ecosistema completo para organización y gestión de contenido con interfaces espaciales

🌐 Universal Animation System - Use Anywhere!

One animation system. Infinite possibilities. Use it everywhere across your entire monorepo.


🎯 Philosophy

The Animation Presets Gallery isn't just for scroll triggers - it's a universal animation system that works:


🚀 Usage Modes

1. Gallery Mode (Showcase)

Use Case: Display all animations for users to explore

import { AnimationPresetsGalleryComponent } from '@widgets-editor/scroll-trigger';

@Component({
  template: `
    <!-- Pure showcase - no integration features -->
    <lib-animation-presets-gallery mode="gallery">
    </lib-animation-presets-gallery>
  `
})

Features in Gallery Mode:

2. Integration Mode (Default)

Use Case: Pick animations to apply to elements

@Component({
  template: `
    <!-- Full integration features -->
    <lib-animation-presets-gallery 
      mode="integration"
      (presetApplied)="applyToElement($event)"
      (presetSelected)="showPreview($event)">
    </lib-animation-presets-gallery>
  `
})
export class MyComponent {
  applyToElement(preset: FlashAnimationPreset) {
    // Apply animation to your element
    console.log('Applying:', preset);
  }
}

Features in Integration Mode:


🎨 Application Methods

Method 1: Scroll Trigger (Scroll-Based)

Best For: Animations triggered by scrolling

<div enhancedScrollTrigger="my-element"
     [animationPreset]="selectedPreset()"
     [start]="'top bottom'"
     [end]="'80%'"
     [showTriggers]="true">
  Animates on scroll!
</div>

Integration Example:

@Component({
  template: `
    <lib-animation-presets-gallery 
      mode="integration"
      (presetApplied)="currentPreset.set($event)">
    </lib-animation-presets-gallery>

    <div enhancedScrollTrigger="hero"
         [animationPreset]="currentPreset()"
         [start]="'top bottom'"
         [end]="'80%'">
      {{ content }}
    </div>
  `
})
export class MyComponent {
  currentPreset = signal<FlashAnimationPreset>('fade-in');
}

Method 2: Flash Animations (Event-Based)

Best For: Hover, click, focus animations

<button [flashAnim]="selectedPreset()"
        flashAnimTrigger="hover"
        flashAnimSpeed="fast">
  Hover me!
</button>

<div [flashAnim]="selectedPreset()"
     flashAnimTrigger="click">
  Click me!
</div>

<input [flashAnim]="selectedPreset()"
       flashAnimTrigger="focus">

Integration Example:

@Component({
  template: `
    <lib-animation-presets-gallery 
      (presetApplied)="buttonAnimation.set($event)">
    </lib-animation-presets-gallery>

    <button [flashAnim]="buttonAnimation()"
            flashAnimTrigger="hover"
            flashAnimSpeed="elegant">
      Animated Button
    </button>
  `
})
export class MyComponent {
  buttonAnimation = signal<FlashAnimationPreset>('pulse');
}

Method 3: Angular Animations (Native)

Best For: Route transitions, programmatic animations

import { trigger, transition, style, animate } from '@angular/animations';

@Component({
  animations: [
    trigger('fadeIn', [
      transition(':enter', [
        style({ opacity: 0, transform: 'translateY(20px)' }),
        animate('400ms ease-out', style({ opacity: 1, transform: 'translateY(0)' }))
      ])
    ])
  ],
  template: `
    <div [@fadeIn]="animationState()">
      Content
    </div>
  `
})

Map Presets to Angular Animations:

const presetToAngularAnimation = {
  'fade-in': { opacity: [0, 1] },
  'slide-up': { transform: ['translateY(100px)', 'translateY(0)'] },
  'scale-in': { transform: ['scale(0.5)', 'scale(1)'] }
  // ... more mappings
};

Method 4: Pure CSS (No JavaScript)

Best For: Performance-critical animations, simple effects

Step 1: Extract keyframes from preset

// Generate CSS from animation preset
generateCSS(preset: FlashAnimationPreset): string {
  const keyframes = this.presetKeyframes[preset];
  return `
    @keyframes ${preset} {
      ${keyframes.map((kf, i) => `
        ${i * 100 / (keyframes.length - 1)}% {
          ${Object.entries(kf).map(([k, v]) => `${k}: ${v}`).join(';')}
        }
      `).join('')}
    }
    
    .${preset} {
      animation: ${preset} 600ms ease-out;
    }
  `;
}

Step 2: Apply CSS class

<div class="fade-in">Animated with CSS!</div>

Pre-Generated CSS (add to your global styles):

/* Fade In */
@keyframes fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

/* Slide Up */
@keyframes slide-up {
  0% { opacity: 0; transform: translateY(30px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* Scale In */
@keyframes scale-in {
  0% { opacity: 0; transform: scale(0.8); }
  100% { opacity: 1; transform: scale(1); }
}

/* Apply */
.animate-fade-in { animation: fade-in 600ms ease-out; }
.animate-slide-up { animation: slide-up 600ms ease-out; }
.animate-scale-in { animation: scale-in 600ms ease-out; }

Method 5: Editor-Web Integration

Best For: Visual editor, drag-and-drop builder

// Inside editor-web components
import { AnimationPresetsGalleryComponent } from '@widgets-editor/scroll-trigger';

@Component({
  template: `
    <!-- Animation picker for selected widget -->
    <div class="property-panel">
      <h3>Widget Animations</h3>
      
      <lib-animation-presets-gallery 
        mode="integration"
        (presetApplied)="applyToWidget($event)">
      </lib-animation-presets-gallery>
    </div>
  `
})
export class WidgetPropertiesPanel {
  applyToWidget(preset: FlashAnimationPreset) {
    const widget = this.selectedWidget();
    widget.animation = preset;
    this.saveWidget(widget);
  }
}

🎯 Common Integration Patterns

Pattern 1: Dynamic Preset Switcher

@Component({
  template: `
    <!-- Preset Gallery -->
    <lib-animation-presets-gallery 
      (presetApplied)="activePreset.set($event)">
    </lib-animation-presets-gallery>

    <!-- Live Preview -->
    <div class="preview-area">
      <h3>Preview: {{ activePreset() }}</h3>
      <div [flashAnim]="activePreset()"
           flashAnimTrigger="manual"
           #previewElement>
        Preview Content
      </div>
      <button (click)="triggerPreview()">Play Animation</button>
    </div>
  `
})
export class DynamicSwitcher {
  activePreset = signal<FlashAnimationPreset>('fade-in');
  @ViewChild('previewElement') previewEl!: ElementRef;

  triggerPreview() {
    // Manually trigger animation
    this.flashAnimController.trigger(this.previewEl.nativeElement, this.activePreset());
  }
}

Pattern 2: Multi-Element Control

@Component({
  template: `
    <!-- Control Panel -->
    <lib-animation-presets-gallery 
      (presetApplied)="applyToAll($event)">
    </lib-animation-presets-gallery>

    <!-- Multiple Elements -->
    @for (item of items(); track item.id) {
      <div [flashAnim]="item.animation"
           flashAnimTrigger="hover">
        {{ item.label }}
      </div>
    }
  `
})
export class MultiElementController {
  items = signal([
    { id: 1, label: 'Item 1', animation: 'fade-in' },
    { id: 2, label: 'Item 2', animation: 'slide-up' }
  ]);

  applyToAll(preset: FlashAnimationPreset) {
    this.items.update(items =>
      items.map(item => ({ ...item, animation: preset }))
    );
  }
}

Pattern 3: Context-Aware Application

@Component({
  template: `
    <!-- Context Selector -->
    <select [(ngModel)]="targetContext">
      <option value="hover">On Hover</option>
      <option value="click">On Click</option>
      <option value="scroll">On Scroll</option>
    </select>

    <lib-animation-presets-gallery 
      (presetApplied)="applyWithContext($event)">
    </lib-animation-presets-gallery>

    <!-- Conditional Application -->
    @switch (targetContext) {
      @case ('hover') {
        <div [flashAnim]="currentPreset()"
             flashAnimTrigger="hover">
          Hover Effect
        </div>
      }
      @case ('click') {
        <button [flashAnim]="currentPreset()"
                flashAnimTrigger="click">
          Click Effect
        </button>
      }
      @case ('scroll') {
        <div [enhancedScrollTrigger]="'scroll-elem'"
             [animationPreset]="currentPreset()">
          Scroll Effect
        </div>
      }
    }
  `
})
export class ContextAwareApplicator {
  targetContext = 'hover';
  currentPreset = signal<FlashAnimationPreset>('pulse');

  applyWithContext(preset: FlashAnimationPreset) {
    this.currentPreset.set(preset);
    console.log(`Applied ${preset} to ${this.targetContext} context`);
  }
}

📦 Exporting for Reuse

Export Animation Configs

// Export current animation setup
exportAnimationConfig() {
  const config = {
    preset: this.currentPreset(),
    trigger: this.triggerType(),
    speed: this.animationSpeed(),
    delay: this.animationDelay()
  };
  
  // Download as JSON
  const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `animation-config-${config.preset}.json`;
  a.click();
}

// Import animation config
importAnimationConfig(file: File) {
  const reader = new FileReader();
  reader.onload = (e) => {
    const config = JSON.parse(e.target.result as string);
    this.applyConfig(config);
  };
  reader.readAsText(file);
}

Share via URL

// Generate shareable URL with animation config
shareAnimation() {
  const config = btoa(JSON.stringify({
    preset: this.currentPreset(),
    trigger: this.triggerType()
  }));
  
  const url = `${window.location.origin}/preview?config=${config}`;
  navigator.clipboard.writeText(url);
}

// Parse config from URL
ngOnInit() {
  const params = new URLSearchParams(window.location.search);
  const configStr = params.get('config');
  if (configStr) {
    const config = JSON.parse(atob(configStr));
    this.applyConfig(config);
  }
}

🎭 Best Practices

1. Choose the Right Method

Use Case Best Method Why
Scroll-based animations Scroll Trigger Built-in viewport detection
Interactive elements Flash Animations Event-based, performant
Route transitions Angular Animations Native integration
Static pages CSS Zero JS overhead
Visual builder Integration Mode User-friendly picker

2. Performance Tips

// ✅ Good: Reuse animation instances
const fadeIn = signal<FlashAnimationPreset>('fade-in');

// ❌ Bad: Create new animations constantly
() => Math.random() > 0.5 ? 'fade-in' : 'slide-up'

// ✅ Good: Batch updates
this.items.update(items => 
  items.map(item => ({ ...item, animation: newPreset }))
);

// ❌ Bad: Update one by one
this.items().forEach((item, i) => {
  this.items.update(items => {
    items[i].animation = newPreset;
    return [...items];
  });
});

3. Accessibility

// Respect user preferences
@Component({
  template: `
    <div [flashAnim]="prefersReducedMotion() ? undefined : activePreset()">
      Content
    </div>
  `
})
export class AccessibleAnimations {
  prefersReducedMotion = signal(
    window.matchMedia('(prefers-reduced-motion: reduce)').matches
  );
}

🎉 Summary

One Animation System. Everywhere.

Ready to animate everything? Pick a preset and go! 🚀