Ux Floating Menu

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

UxFloatingMenu Component

Overview

The UxFloatingMenuComponent is a modern, performant floating menu component designed for displaying action buttons in a fixed position on the screen. It features a glassmorphism design, smooth animations, and full accessibility support.

Features

Installation

Import the Component

The component is part of the @ux-menu library. Use direct imports for reliability:

import { UxFloatingMenuComponent } from 'libs/ux-menu/src/lib/components/ux-floating-menu/ux-floating-menu.component';
import { UxFloatingMenuItem } from 'libs/ux-menu/src/lib/models/ux-floating-menu.models';

Add to Component Imports

@Component({
  selector: 'app-my-component',
  standalone: true,
  imports: [UxFloatingMenuComponent],
  // ...
})
export class MyComponent {}

Basic Usage

Simple Example

import { Component, signal } from '@angular/core';
import { UxFloatingMenuComponent } from 'libs/ux-menu/src/lib/components/ux-floating-menu/ux-floating-menu.component';
import { UxFloatingMenuItem } from 'libs/ux-menu/src/lib/models/ux-floating-menu.models';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [UxFloatingMenuComponent],
  template: `
    <ux-floating-menu
      [items]="menuItems()"
      position="bottom-right" />
  `
})
export class ExampleComponent {
  menuItems = signal<UxFloatingMenuItem[]>([
    {
      id: 'ai-assistant',
      icon: 'svg/robot',
      label: 'AI Assistant',
      onClick: () => this.openAIAssistant()
    },
    {
      id: 'settings',
      icon: 'svg/settings',
      label: 'Settings',
      onClick: () => this.openSettings()
    }
  ]);

  openAIAssistant(): void {
    console.log('Opening AI Assistant...');
  }

  openSettings(): void {
    console.log('Opening Settings...');
  }
}

Advanced Usage

With Notifications and Active States

menuItems = signal<UxFloatingMenuItem[]>([
  {
    id: 'notifications',
    icon: 'svg/bell',
    label: 'Notifications',
    notificationCount: 5,
    onClick: (item) => this.handleNotifications(item)
  },
  {
    id: 'messages',
    icon: 'svg/message',
    label: 'Messages',
    active: true, // Currently active
    notificationCount: 12,
    onClick: (item) => this.handleMessages(item)
  },
  {
    id: 'archive',
    icon: 'svg/archive',
    label: 'Archive',
    disabled: true, // Disabled state
    tooltip: 'Archive feature coming soon'
  }
]);

Custom Configuration

<ux-floating-menu
  [items]="menuItems()"
  position="top-left"
  [config]="{
    showWhenHidden: true,
    animationDuration: 400,
    gap: '12px'
  }" />

With Custom Styling

menuItems = signal<UxFloatingMenuItem[]>([
  {
    id: 'custom',
    icon: 'svg/star',
    label: 'Custom',
    styleClass: 'my-custom-button-class',
    onClick: () => this.handleCustomAction()
  }
]);

Add custom styles in your component's SCSS:

::ng-deep {
  .my-custom-button-class {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
    border-color: rgba(102, 126, 234, 0.5) !important;
  }
}

Dynamic Menu Items

import { Component, signal, computed } from '@angular/core';

@Component({
  // ...
})
export class DynamicMenuComponent {
  private hasNewMessages = signal(true);
  private messageCount = signal(3);
  private isAdminMode = signal(false);

  menuItems = computed<UxFloatingMenuItem[]>(() => {
    const items: UxFloatingMenuItem[] = [
      {
        id: 'messages',
        icon: 'svg/message',
        label: 'Messages',
        notificationCount: this.hasNewMessages() ? this.messageCount() : 0,
        onClick: () => this.openMessages()
      },
      {
        id: 'help',
        icon: 'svg/help',
        label: 'Help',
        onClick: () => this.openHelp()
      }
    ];

    // Conditionally add admin item
    if (this.isAdminMode()) {
      items.push({
        id: 'admin',
        icon: 'svg/shield',
        label: 'Admin Panel',
        onClick: () => this.openAdminPanel()
      });
    }

    return items;
  });
}

API Reference

Inputs

Input Type Default Description
items UxFloatingMenuItem[] required Array of menu items to display
position UxFloatingMenuPosition 'bottom-right' Position of the menu on screen
config UxFloatingMenuConfig {} Additional configuration options

UxFloatingMenuItem Interface

interface UxFloatingMenuItem {
  id: string;                    // Unique identifier
  icon: string;                  // Icon ID for ux-icon component
  label: string;                 // Display label
  onClick?: (item: UxFloatingMenuItem, event?: Event) => void;  // Click handler
  active?: boolean;              // Active/selected state
  notificationCount?: number;    // Notification badge count
  disabled?: boolean;            // Disabled state
  tooltip?: string;              // Tooltip text
  ariaLabel?: string;            // Accessibility label
  styleClass?: string;           // Custom CSS classes
  hidden?: boolean;              // Hide item
}

UxFloatingMenuPosition Type

type UxFloatingMenuPosition = 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left';

UxFloatingMenuConfig Interface

interface UxFloatingMenuConfig {
  position?: UxFloatingMenuPosition;  // Menu position (overridden by position input)
  showWhenHidden?: boolean;           // Show toggle button
  animationDuration?: number;         // Animation duration in ms
  gap?: string;                       // Gap between items (CSS value)
}

Methods

The component provides these public methods:

// Toggle menu visibility
toggleVisibility(): void

// Get total notification count
getTotalNotifications(): number

// Check if any item is active
hasActiveItem(): boolean

Accessibility Features

The component is fully accessible and includes:

Styling Customization

CSS Variables

The component uses CSS variables for easy theming:

:root {
  --ux-floating-menu-gap: 8px;
  --ux-text-color: #e2e8f0;
  --ux-focus-color: #3b82f6;
}

Custom Styles

You can override component styles using the styleClass property on individual items or by targeting component classes:

// In your component's styles
::ng-deep {
  .ux-floating-menu__item {
    // Custom item styles
  }
  
  .ux-floating-menu__badge {
    // Custom badge styles
  }
}

Performance Considerations

Browser Support

Examples

Complete Real-World Example

import { Component, signal } from '@angular/core';
import { UxFloatingMenuComponent } from 'libs/ux-menu/src/lib/components/ux-floating-menu/ux-floating-menu.component';
import { UxFloatingMenuItem } from 'libs/ux-menu/src/lib/models/ux-floating-menu.models';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [UxFloatingMenuComponent],
  template: `
    <div class="dashboard">
      <!-- Your dashboard content -->
      
      <ux-floating-menu
        [items]="floatingActions()"
        position="bottom-right"
        [config]="{ showWhenHidden: false }" />
    </div>
  `
})
export class DashboardComponent {
  showAI = signal(false);
  showLibrary = signal(false);
  aiSuggestions = signal(3);
  
  floatingActions = signal<UxFloatingMenuItem[]>([
    {
      id: 'ai-assistant',
      icon: 'svg/robot',
      label: 'AI Assistant',
      notificationCount: this.aiSuggestions(),
      active: this.showAI(),
      onClick: () => this.toggleAI(),
      ariaLabel: 'Toggle AI Assistant'
    },
    {
      id: 'library',
      icon: 'svg/library',
      label: 'Component Library',
      active: this.showLibrary(),
      onClick: () => this.toggleLibrary(),
      ariaLabel: 'Toggle Component Library'
    },
    {
      id: 'export',
      icon: 'svg/download',
      label: 'Export',
      onClick: () => this.handleExport(),
      tooltip: 'Export your project'
    },
    {
      id: 'reset',
      icon: 'svg/refresh',
      label: 'Reset View',
      onClick: () => this.resetView(),
      tooltip: 'Reset to default view'
    }
  ]);
  
  toggleAI(): void {
    this.showAI.update(value => !value);
    this.updateItemState('ai-assistant', this.showAI());
  }
  
  toggleLibrary(): void {
    this.showLibrary.update(value => !value);
    this.updateItemState('library', this.showLibrary());
  }
  
  updateItemState(id: string, active: boolean): void {
    this.floatingActions.update(items =>
      items.map(item =>
        item.id === id ? { ...item, active } : item
      )
    );
  }
  
  handleExport(): void {
    console.log('Exporting project...');
  }
  
  resetView(): void {
    console.log('Resetting view...');
  }
}

Related Components

Troubleshooting

Icons not displaying

Make sure the icon IDs you're using exist in your icon service:

// Verify icon exists
icon: 'svg/robot' // Must be available in icon service

Menu not positioning correctly

Check that the parent container allows fixed positioning:

.parent-container {
  position: relative; // or static, but not absolute/fixed
  z-index: 1; // Lower than menu's z-index (100)
}

Styles not applying

Use direct imports and ensure your build includes the component:

import { UxFloatingMenuComponent } from 'libs/ux-menu/src/lib/components/ux-floating-menu/ux-floating-menu.component';

Changelog

Version 1.0.0 (October 2024)