Appearance
Widget Context (xctx)
Widget Context (xctx) is a special object containing information about the widget's operating environment and state. It centrally manages container, dimensions, settings, and environmental information.
Basic Structure
typescript
interface WidgetContext {
container: HTMLElement; // DOM element where the widget will be rendered
scope: any; // Widget scope data
width: number; // Widget width
height: number; // Widget height
settings: WidgetSettings; // Widget settings
dataSources: any[]; // Data sources
isMobile: boolean; // Mobile device check
isEdit: boolean; // In edit mode?
isPreview?: boolean; // In preview mode?
isFullscreen?: boolean; // In fullscreen mode?
[key: string]: any; // Additional properties
}Basic Usage
Accessing Context Information
Context with Computed Properties
typescript
@Widget({
selector: '.responsive-widget',
template: `
<div x:class:compact="isCompact" x:class:mobile="isMobileLayout">
<h3 x:text="layoutMode">Layout</h3>
<p x:text="message">Message</p>
</div>
`
})
export class ResponsiveWidget {
@xcomputed({ dependencies: ['xctx.width'] })
get isCompact(): boolean {
return (this.xctx?.width || 0) < 400;
}
@xcomputed({ dependencies: ['xctx.isMobile'] })
get isMobileLayout(): boolean {
return this.xctx?.isMobile || false;
}
@xcomputed({ dependencies: ['xctx.width', 'xctx.isMobile'] })
get layoutMode(): string {
if (this.xctx?.isMobile) return 'Mobile View';
return (this.xctx?.width || 0) < 600 ? 'Compact View' : 'Normal View';
}
@xcomputed({ dependencies: ['xctx.isEdit'] })
get message(): string {
return this.xctx?.isEdit ?
'You are working in edit mode' :
'You are viewing content';
}
}Container Operations
Accessing Container
typescript
@Widget({
selector: '.container-widget',
template: `
<div class="container-operations">
<button x:on:click="addToContainer">Add to Container</button>
<button x:on:click="checkContainer">Check Container</button>
<p x:text="containerInfo">Container info</p>
</div>
`
})
export class ContainerWidget {
@xproperty()
containerInfo: string = '';
addToContainer(): void {
const container = this.xctx?.container;
if (container && container.isConnected) {
const newElement = document.createElement('div');
newElement.textContent = `New element - ${new Date().toLocaleTimeString()}`;
newElement.className = 'dynamic-item';
container.appendChild(newElement);
this.containerInfo = `Element added: ${container.children.length} children`;
}
}
checkContainer(): void {
const container = this.xctx?.container;
if (container) {
this.containerInfo = `
Tag: ${container.tagName}
ID: ${container.id || 'none'}
Children: ${container.children.length}
`;
}
}
}Settings Management
Using Widget Settings
typescript
interface MyWidgetSettings {
theme: 'light' | 'dark';
language: string;
autoRefresh: boolean;
}
@Widget({
selector: '.settings-widget',
template: `
<div x:class:dark-theme="isDarkTheme">
<h3>Widget Settings</h3>
<p>Theme: <span x:text="currentTheme">-</span></p>
<p>Language: <span x:text="currentLanguage">-</span></p>
<p>Auto Refresh: <span x:text="autoRefreshStatus">-</span></p>
<button x:on:click="toggleTheme">Toggle Theme</button>
</div>
`
})
export class SettingsWidget implements OnWidgetReady {
@xproperty()
currentTheme: string = 'light';
@xproperty()
currentLanguage: string = 'tr';
@xcomputed({ dependencies: ['currentTheme'] })
get isDarkTheme(): boolean {
return this.currentTheme === 'dark';
}
@xcomputed({ dependencies: ['xctx.settings.autoRefresh'] })
get autoRefreshStatus(): string {
const settings = this.xctx?.settings as MyWidgetSettings;
return settings?.autoRefresh ? 'On' : 'Off';
}
onWidgetReady(): void {
const settings = this.xctx?.settings as MyWidgetSettings;
if (settings) {
this.currentTheme = settings.theme || 'light';
this.currentLanguage = settings.language || 'tr';
}
}
toggleTheme(): void {
if (this.xctx?.settings) {
const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
this.currentTheme = newTheme;
(this.xctx.settings as MyWidgetSettings).theme = newTheme;
}
}
}Direct Context Usage in Template
Binding with xctx
typescript
@Widget({
selector: '.direct-context-widget',
template: `
<div class="context-bindings">
<!-- Direct access to context values -->
<p>Width: <span x:text="xctx.width || 0">0</span>px</p>
<p>Height: <span x:text="xctx.height || 0">0</span>px</p>
<p>Mobile: <span x:text="xctx.isMobile ? 'Yes' : 'No'">No</span></p>
<!-- Conditional rendering -->
<div x:class:visible="xctx.isEdit" class="edit-panel">
<h4>Editing Tools</h4>
<button x:on:click="save">Save</button>
</div>
<!-- Responsive layout -->
<div
x:class:mobile-layout="xctx.isMobile"
x:class:desktop-layout="!xctx.isMobile">
<p x:text="layoutMessage">Layout</p>
</div>
</div>
`,
styles: [`
.edit-panel {
display: none;
background: #fff3cd;
padding: 15px;
border-radius: 6px;
}
.edit-panel.visible {
display: block;
}
.mobile-layout { font-size: 14px; }
.desktop-layout { font-size: 16px; }
`]
})
export class DirectContextWidget {
@xcomputed({ dependencies: ['xctx.isMobile'] })
get layoutMessage(): string {
return this.xctx?.isMobile ?
'Mobile optimization active' :
'Desktop full features';
}
save(): void {
console.log('Changes saved');
}
}Context Updates
Dynamic Context Updates
typescript
@Widget({
selector: '.update-context-widget',
template: `
<div class="update-controls">
<h3>Context Update</h3>
<div class="control-group">
<label>Custom Data:</label>
<input type="text" x:model="newData">
<button x:on:click="updateCustomData">Update</button>
</div>
<div class="control-group">
<button x:on:click="toggleFullscreen">Fullscreen</button>
<button x:on:click="refreshContext">Refresh</button>
</div>
<div class="context-display">
<pre x:text="contextSummary">Loading context info...</pre>
</div>
</div>
`
})
export class UpdateContextWidget implements OnWidgetReady {
@xproperty()
newData: string = '';
@xproperty()
contextSummary: string = '';
onWidgetReady(): void {
this.refreshContext();
}
updateCustomData(): void {
if (this.xctx && this.newData) {
// Adding custom data to context
this.xctx.customData = this.newData;
this.newData = '';
this.refreshContext();
}
}
toggleFullscreen(): void {
if (this.xctx) {
this.xctx.isFullscreen = !this.xctx.isFullscreen;
this.refreshContext();
}
}
refreshContext(): void {
if (this.xctx) {
this.contextSummary = `
Width: ${this.xctx.width || 0}px
Height: ${this.xctx.height || 0}px
Mobile: ${this.xctx.isMobile ? 'Yes' : 'No'}
Edit Mode: ${this.xctx.isEdit ? 'Yes' : 'No'}
Fullscreen: ${this.xctx.isFullscreen ? 'Yes' : 'No'}
`.trim();
}
}
}Best Practices
1. Null Safety
typescript
// Always check xctx existence
if (this.xctx?.container) {
// Safe context operations
}
// Use default values
const width = this.xctx?.width || 0;
const isMobile = this.xctx?.isMobile || false;2. Responsive Design
typescript
@xcomputed({ dependencies: ['xctx.width'] })
get isCompactMode(): boolean {
return (this.xctx?.width || 0) < 400;
}
@xcomputed({ dependencies: ['xctx.isMobile', 'xctx.width'] })
get deviceType(): string {
if (this.xctx?.isMobile) return 'mobile';
return (this.xctx?.width || 0) < 768 ? 'tablet' : 'desktop';
}3. Container Safety
typescript
// Safety check in container operations
private safeContainerOperation(): void {
const container = this.xctx?.container;
if (container && container.isConnected) {
// Safe DOM operations
}
}4. Settings Management
typescript
// Use settings in a type-safe way
interface MySettings {
option1: string;
option2: boolean;
}
private getSettings(): MySettings | undefined {
return this.xctx?.settings as MySettings;
}
updateSetting(key: keyof MySettings, value: any): void {
const settings = this.getSettings();
if (settings) {
settings[key] = value;
}
}Summary
Widget Context (xctx) features:
✅ Container Reference - Direct access to DOM container
✅ Dimension Information - width, height tracking
✅ Responsive Behavior - isMobile, device detection
✅ Mode Control - isEdit, isPreview, isFullscreen
✅ Settings Configuration - Managing widget settings
✅ Template Binding - Direct xctx usage
✅ Dynamic Updates - Runtime context changes
Context is a powerful and flexible system that centrally manages the widget's operating environment.