Appearance
@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 riskError 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:
- Defines widget configuration
- Performs automatic registry registration
- Provides template and style management
- Offers encapsulation modes
- Performs lifecycle integration
- Establishes reactive system connection
- 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.