import { DeesElement, property, html, customElement, type TemplateResult, state } from '@design.estate/dees-element'; import { WccDashboard } from './wcc-dashboard.js'; export type TPropertyType = 'String' | 'Number' | 'Boolean' | 'Object' | 'Enum' | 'Array'; export type TEnvironment = 'native' | 'desktop' | 'tablet' | 'phablet' | 'phone'; export type TTheme = 'bright' | 'dark'; let environment: TEnvironment = 'native'; export const setEnvironment = (envArg) => { environment = envArg; }; @customElement('wcc-properties') export class WccProperties extends DeesElement { @property({ type: WccDashboard }) public dashboardRef: WccDashboard; @property() public selectedItem: (() => TemplateResult) | DeesElement; @property() public selectedViewport: TEnvironment = 'native'; @property() public selectedTheme: TTheme = 'dark'; @property() public warning: string = null; @state() propertyContent: TemplateResult[] = []; public render(): TemplateResult { return html`
Properties
${this.propertyContent}
Theme
{ this.selectTheme('dark'); }} > Dark
brightness_3
{ this.selectTheme('bright'); }} > Bright
flare
Viewport
{ this.selectViewport('phone'); }} > Phone
smartphone
{ this.selectViewport('phablet'); }} > Phablet
smartphone
{ this.selectViewport('tablet'); }} > Tablet
tablet
{ this.selectViewport('native'); }} > Desktop
desktop_windows
Docs
${this.warning ? html`
${this.warning}
` : null} `; } private async findElementRecursively(container: Element, elementClass: any, maxDepth: number = 5): Promise { if (maxDepth <= 0) return null; try { // Check direct children for (const child of Array.from(container.children)) { if (child instanceof elementClass) { return child as HTMLElement; } } // Search in all children recursively for (const child of Array.from(container.children)) { // First, always check the light DOM children const found = await this.findElementRecursively(child, elementClass, maxDepth - 1); if (found) return found; // Also check shadow root if it exists if (child.shadowRoot) { const shadowFound = await this.findElementRecursively(child.shadowRoot as any, elementClass, maxDepth - 1); if (shadowFound) return shadowFound; } } } catch (error) { console.error('Error in findElementRecursively:', error); } return null; } public async createProperties() { console.log('creating properties for:'); console.log(this.selectedItem); // Clear any previous warnings this.warning = null; const isEnumeration = (propertyArg): boolean => { const keys = Object.keys(propertyArg.type); const values = []; for (const key of keys) { let value = propertyArg.type[key]; if (typeof value === 'number') { value = value.toString(); } values.push(value); } for (const key of keys) { if (values.indexOf(key) < 0) { return false; } } return true; }; const getEnumValues = (propertyArg): any[] => { console.log(JSON.stringify(propertyArg)); const enumValues: any[] = []; Object.keys(propertyArg.type).forEach((valueArg: string) => { enumValues.push(valueArg); }); return enumValues; }; const determinePropertyType = async (propertyArg: any): Promise => { const typeName: any | undefined = propertyArg.type.name; if (typeName) { return typeName; } else { return Array.isArray(propertyArg) ? 'Array' : isEnumeration(propertyArg) ? 'Enum' : 'Object'; } }; if (this.selectedItem && (this.selectedItem as any).demo) { console.log(`Got Dees-Element for property evaluation.`); const anonItem: any = this.selectedItem; if (!anonItem) { this.warning = 'no element selected'; return; } console.log(anonItem.elementProperties); const wccFrame = await this.dashboardRef.wccFrame; // Wait for render to complete and any demo wrappers to run await new Promise(resolve => setTimeout(resolve, 200)); // Try to find the element with recursive search const viewport = await wccFrame.getViewportElement(); let firstFoundInstantiatedElement: HTMLElement = await this.findElementRecursively( viewport, this.selectedItem as any ); // Retry logic if element not found let retries = 0; while (!firstFoundInstantiatedElement && retries < 5) { await new Promise(resolve => setTimeout(resolve, 200)); try { firstFoundInstantiatedElement = await this.findElementRecursively( viewport, this.selectedItem as any ); } catch (error) { console.error('Error during element search retry:', error); } retries++; } if (!firstFoundInstantiatedElement) { this.warning = `no first instantiated element found for >>${anonItem.name}<< after ${retries} retries`; this.propertyContent = []; return; } const classProperties: Map = anonItem.elementProperties; if (!classProperties) { this.warning = `selected element >>${anonItem.name}<< does not expose element properties`; return; } this.warning = null; const propertyArray: TemplateResult[] = []; for (const key of classProperties.keys()) { if (key === 'goBright' || key === 'domtools') { continue; } try { const property = classProperties.get(key); const propertyTypeString = await determinePropertyType(property); propertyArray.push( html`
${key} / ${propertyTypeString}
${(() => { switch (propertyTypeString) { case 'Boolean': return html``; case 'String': return html``; case 'Number': return html``; case 'Enum': const enumValues: any[] = getEnumValues(property); return html``; } })()}
` ); } catch (error) { console.error(`Error processing property ${key}:`, error); // Continue with next property even if this one fails } } this.propertyContent = propertyArray; } else { console.log(`Cannot extract properties of ${(this.selectedItem as any)?.name}`); this.warning = `You selected a page.`; return null; } } public selectTheme(themeArg: TTheme) { this.selectedTheme = themeArg; this.dispatchEvent( new CustomEvent('selectedTheme', { detail: themeArg, }) ); console.log(this.dashboardRef.selectedType); this.dashboardRef.buildUrl(); } public async scheduleUpdate() { try { await this.createProperties(); } catch (error) { console.error('Error creating properties:', error); // Clear property content on error to show clean state this.propertyContent = []; } // Always call super.scheduleUpdate to ensure component updates super.scheduleUpdate(); } public selectViewport(viewport: TEnvironment) { this.selectedViewport = viewport; setEnvironment(viewport); this.dispatchEvent( new CustomEvent('selectedViewport', { detail: viewport, }) ); this.dashboardRef.buildUrl(); } }