Skip to content

@Widget Decorator

The @Widget decorator converts TypeScript classes into widgets compatible with the XCon Widget Framework. It defines widget configuration and performs automatic registry registration.

Basic Usage

typescript
import { Widget } from '@xcons/widget';

@Widget({
  widgetName: 'MyWidget',
  selector: '.my-widget',
  template: '<div>Hello Widget!</div>'
})
export class MyWidget {
  // Widget implementation
}

Configuration Options

Basic Properties

typescript
@Widget({
  // Widget definition
  widgetName: 'MyCustomWidget',
  widgetDescription: 'Custom widget description',
  widgetVersion: '1.0.0',
  
  // DOM selector (required)
  selector: '.my-widget',
  
  // Initialization mode
  initMode: 'auto' // 'auto' | 'manual'
})

Template Configuration

typescript
@Widget({
  widgetName: 'TemplateWidget',
  selector: '.template-widget',
  
  // Inline template
  template: `
    <div class="widget-container">
      <h1 x:text="title"></h1>
      <button x:on:click="handleClick">Click</button>
    </div>
  `,
  
  // Or external template file
  templateUrl: './templates/widget-template.html'
})

Style Configuration

typescript
@Widget({
  widgetName: 'StyledWidget',
  selector: '.styled-widget',
  template: '<div class="content">Content</div>',
  
  // Inline styles
  styles: [
    `.content {
      padding: 20px;
      background: #f5f5f5;
      border-radius: 8px;
    }`,
    `.content:hover {
      background: #e0e0e0;
    }`
  ],
  
  // External CSS files
  styleUrls: [
    './styles/widget.css',
    './styles/theme.css'
  ]
})

Encapsulation Modes

typescript
// Global styles (default)
@Widget({
  selector: '.global-widget',
  encapsulation: 'none',
  styles: ['h1 { color: red; }'] // Affects entire page
})

// Emulated encapsulation
@Widget({
  selector: '.scoped-widget',
  encapsulation: 'emulated',
  styles: ['h1 { color: blue; }'] // Only affects widget interior
})

// Shadow DOM
@Widget({
  selector: '.shadow-widget',
  encapsulation: 'shadow',
  styles: [':host { display: block; border: 1px solid gray; }']
})

// XCon-style component
@Widget({
  selector: '.component-widget',
  encapsulation: 'component',
  styles: ['.content { padding: 10px; }']
})

Logger Configuration

typescript
@Widget({
  widgetName: 'LoggedWidget',
  selector: '.logged-widget',
  
  logger: {
    enabled: true,
    level: LoggerLogLevel.DEBUG,
    timestamp: true,
    colors: true,
    componentLogLevel: ComponentLogLevel.DETAILED
  }
})

Initialization Modes

Auto Mode (Default)

typescript
@Widget({
  selector: '.auto-widget',
  initMode: 'auto' // Automatically initialized when found in DOM
})
export class AutoWidget {
  // init() is called automatically and template is applied
}

Manual Mode

typescript
@Widget({
  selector: '.manual-widget',
  initMode: 'manual' // Manual control
})
export class ManualWidget {
  async customInit() {
    // Custom initialization logic
    await this.init();
    this.applyTemplate();
  }
}

Registry Integration

The @Widget decorator automatically registers the widget to the global registry:

typescript
@Widget({
  selector: '.registered-widget',
  widgetName: 'RegisteredWidget'
})
export class RegisteredWidget {}

// Automatically added to registry
console.log(XConWidgets.isRegistered('.registered-widget')); // true
console.log(XConWidgets.getWidgets()); // ['.registered-widget', ...]

Lifecycle Integration

typescript
import { Widget } from '@xcons/widget';
import type { OnWidgetInit, OnWidgetReady, OnWidgetDestroy } from '@xcons/widget';

@Widget({
  widgetName: 'LifecycleWidget',
  selector: '.lifecycle-widget',
  template: '<div>Lifecycle Widget</div>'
})
export class LifecycleWidget implements OnWidgetInit, OnWidgetReady, OnWidgetDestroy {
  
  async onWidgetInit(): Promise<void> {
    console.log('Widget is initializing...');
  }
  
  onWidgetReady(templateReady: boolean): void {
    console.log('Widget ready:', templateReady);
  }
  
  onWidgetDestroy(): void {
    console.log('Widget is being cleaned up...');
  }
}

Reactive System Integration

typescript
import { Widget, xproperty, xcomputed } from '@xcons/widget';

@Widget({
  widgetName: 'ReactiveWidget',
  selector: '.reactive-widget',
  template: `
    <div>
      <p x:text="message"></p>
      <p x:text="computedValue"></p>
      <button x:on:click="updateMessage">Update</button>
    </div>
  `
})
export class ReactiveWidget {
  
  @xproperty()
  message: string = 'Hello!';
  
  @xcomputed({ dependencies: ['message'] })
  get computedValue(): string {
    return `Computed: ${this.message.toUpperCase()}`;
  }
  
  updateMessage() {
    this.message = `Updated: ${Date.now()}`;
  }
}

Selector Requirements

Each widget must have a unique selector. Use valid CSS selector format:

typescript
// ✅ Good examples
@Widget({ selector: '.user-profile' })      // Class selector
@Widget({ selector: '#dashboard-widget' })  // ID selector
@Widget({ selector: '[data-widget="calendar"]' }) // Attribute selector
@Widget({ selector: 'custom-element' })     // Element selector

// ⌠Bad examples
@Widget({ selector: '' })           // Empty selector
@Widget({ selector: 'div' })        // Too general
@Widget({ selector: '.widget' })    // Too general, collision risk

Error Handling

typescript
import type { OnWidgetInitializationError } from '@xcons/widget';

@Widget({
  widgetName: 'ErrorHandlingWidget',
  selector: '.error-widget',
  template: '<div>Error Widget</div>'
})
export class ErrorHandlingWidget implements OnWidgetInitializationError {
  
  onWidgetInitializationError(error: any): void {
    this.safeLog('error', 'Widget initialization error:', error);
    // Error handling logic
  }
}

Complete Configuration Example

Summary

The @Widget decorator:

  1. Defines widget configuration
  2. Performs automatic registry registration
  3. Provides template and style management
  4. Offers encapsulation modes
  5. Performs lifecycle integration
  6. Establishes reactive system connection
  7. Provides error handling support

With this decorator, TypeScript classes are converted into fully-featured, reactive widgets and automatically managed within the XCon Widget Framework ecosystem.