Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
e11f0df950 | |||
c64b106569 | |||
3d1948b93e | |||
21b7158a35 | |||
992af2668e | |||
0cd84b28b4 | |||
0709267bd5 | |||
d4fce8a939 | |||
578f87a8f9 | |||
0acf341071 | |||
87bbf0bbdc |
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@design.estate/dees-wcctools",
|
"name": "@design.estate/dees-wcctools",
|
||||||
"version": "1.0.92",
|
"version": "1.0.98",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.",
|
"description": "A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist_ts_web/index.js",
|
".": "./dist_ts_web/index.js",
|
||||||
"./demoTools": "./dist_ts_demotools"
|
"./demotools": "./dist_ts_demotools/index.js"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -12,16 +12,24 @@ The properties panel had timing issues detecting rendered elements because:
|
|||||||
1. Added a 100ms initial delay to allow render completion
|
1. Added a 100ms initial delay to allow render completion
|
||||||
2. Implemented recursive element search that:
|
2. Implemented recursive element search that:
|
||||||
- Searches through nested children up to 5 levels deep
|
- Searches through nested children up to 5 levels deep
|
||||||
- Checks shadow roots of elements
|
- Checks both light DOM and shadow DOM for all elements
|
||||||
- Handles complex DOM structures
|
- Handles complex DOM structures generically
|
||||||
|
- Works with any wrapper elements, not specific to dees-demowrapper
|
||||||
3. Added retry mechanism with up to 5 attempts (200ms between retries)
|
3. Added retry mechanism with up to 5 attempts (200ms between retries)
|
||||||
4. Improved error messages to show retry count
|
4. Improved error messages to show retry count
|
||||||
|
5. Comprehensive error handling:
|
||||||
|
- Errors in element search don't break the update cycle
|
||||||
|
- Individual property errors don't prevent other properties from rendering
|
||||||
|
- scheduleUpdate always completes even if createProperties fails
|
||||||
|
- Clears warnings and property content appropriately on errors
|
||||||
|
|
||||||
### Code Flow
|
### Code Flow
|
||||||
1. Dashboard renders element demo into viewport using `render(anonItem.demo(), viewport)`
|
1. Dashboard renders element demo into viewport using `render(anonItem.demo(), viewport)`
|
||||||
2. Properties panel waits, then searches recursively for the element instance
|
2. Properties panel waits 200ms for demo wrappers to run and set initial values
|
||||||
3. If not found, retries with delays to handle async rendering
|
3. Searches recursively for the element instance
|
||||||
4. Once found, extracts and displays element properties
|
4. If not found, retries with delays to handle async rendering
|
||||||
|
5. Once found, extracts and displays element properties
|
||||||
|
6. Uses property binding (`.value=`) instead of attribute binding to prevent input events during initialization
|
||||||
|
|
||||||
## Demo Tools
|
## Demo Tools
|
||||||
|
|
||||||
@ -30,22 +38,37 @@ A utility component for wrapping demo elements with post-render functionality.
|
|||||||
|
|
||||||
**Usage:**
|
**Usage:**
|
||||||
```typescript
|
```typescript
|
||||||
import { DeesDemoWrapper } from '@design.estate/dees-wcctools/demoTools';
|
import * as demoTools from '@design.estate/dees-wcctools/demotools';
|
||||||
|
|
||||||
// In your demo function:
|
// In your demo function:
|
||||||
demo: () => html`
|
demo: () => html`
|
||||||
<dees-demowrapper .runAfterRender=${(element) => {
|
<dees-demowrapper .runAfterRender=${(wrapper) => {
|
||||||
// Do something with the rendered element
|
// Use querySelector for specific elements
|
||||||
element.setAttribute('data-demo', 'true');
|
const myElement = wrapper.querySelector('my-custom-element');
|
||||||
console.log('Element rendered:', element);
|
myElement?.setAttribute('data-demo', 'true');
|
||||||
|
|
||||||
|
// Access all children
|
||||||
|
console.log('All children:', wrapper.children);
|
||||||
|
|
||||||
|
// Use querySelectorAll for multiple elements
|
||||||
|
wrapper.querySelectorAll('div').forEach(div => {
|
||||||
|
console.log('Found div:', div);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Full DOM API available
|
||||||
|
const firstChild = wrapper.firstElementChild;
|
||||||
|
const hasClass = wrapper.querySelector('.my-class');
|
||||||
}}>
|
}}>
|
||||||
<my-custom-element></my-custom-element>
|
<my-custom-element></my-custom-element>
|
||||||
|
<div>Additional content</div>
|
||||||
</dees-demowrapper>
|
</dees-demowrapper>
|
||||||
`
|
`
|
||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
- Wraps demo elements without affecting layout (uses `display: contents`)
|
- Wraps demo elements without affecting layout (uses `display: contents`)
|
||||||
- Provides access to the rendered element instance after mounting
|
- Provides the wrapper element itself with full DOM API access
|
||||||
|
- Use querySelector/querySelectorAll for powerful element selection
|
||||||
|
- Access children via wrapper.children property
|
||||||
- Supports async operations in runAfterRender callback
|
- Supports async operations in runAfterRender callback
|
||||||
- Automatically handles timing to ensure element is fully rendered
|
- Automatically handles timing to ensure elements are fully rendered
|
54
readme.md
54
readme.md
@ -178,28 +178,34 @@ public static styles = [
|
|||||||
The demo tools provide enhanced testing capabilities:
|
The demo tools provide enhanced testing capabilities:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import * as demoTools from '@design.estate/dees-wcctools/demoTools';
|
import * as demoTools from '@design.estate/dees-wcctools/demotools';
|
||||||
|
|
||||||
@customElement('my-component')
|
@customElement('my-component')
|
||||||
export class MyComponent extends DeesElement {
|
export class MyComponent extends DeesElement {
|
||||||
public static demo = () => html`
|
public static demo = () => html`
|
||||||
<dees-demowrapper .runAfterRender=${async (element: MyComponent) => {
|
<dees-demowrapper .runAfterRender=${async (wrapper) => {
|
||||||
// Access the rendered component instance
|
// Use querySelector to find specific elements
|
||||||
console.log('Component mounted:', element);
|
const myComponent = wrapper.querySelector('my-component') as MyComponent;
|
||||||
|
console.log('Component found:', myComponent);
|
||||||
|
|
||||||
|
// Access all children via wrapper.children
|
||||||
|
console.log('Total children:', wrapper.children.length);
|
||||||
|
|
||||||
|
// Use querySelectorAll for multiple elements
|
||||||
|
const allDivs = wrapper.querySelectorAll('div');
|
||||||
|
console.log('Found divs:', allDivs.length);
|
||||||
|
|
||||||
// Simulate user interactions
|
// Simulate user interactions
|
||||||
element.value = 'Test value';
|
myComponent.value = 'Test value';
|
||||||
await element.updateComplete;
|
await myComponent.updateComplete;
|
||||||
|
|
||||||
// Trigger methods
|
// Work with all children
|
||||||
element.handleClick();
|
Array.from(wrapper.children).forEach((child, index) => {
|
||||||
|
console.log(`Child ${index}:`, child.tagName);
|
||||||
// Assert component state
|
});
|
||||||
if (element.isValid) {
|
|
||||||
console.log('Component validation passed');
|
|
||||||
}
|
|
||||||
}}>
|
}}>
|
||||||
<my-component></my-component>
|
<my-component></my-component>
|
||||||
|
<div>Additional content</div>
|
||||||
</dees-demowrapper>
|
</dees-demowrapper>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -304,10 +310,18 @@ For complex property types, implement custom logic in your demo:
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
public static demo = () => html`
|
public static demo = () => html`
|
||||||
<dees-demowrapper .runAfterRender=${(el) => {
|
<dees-demowrapper .runAfterRender=${(wrapper) => {
|
||||||
// Set up complex property handling
|
// Use querySelector to target specific elements
|
||||||
el.addEventListener('property-change', (e) => {
|
const component = wrapper.querySelector('my-component');
|
||||||
console.log('Property changed:', e.detail);
|
if (component) {
|
||||||
|
component.addEventListener('property-change', (e) => {
|
||||||
|
console.log('Property changed:', e.detail);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or handle all elements of a type
|
||||||
|
wrapper.querySelectorAll('my-component').forEach(el => {
|
||||||
|
el.addEventListener('click', () => console.log('Clicked!'));
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
<my-component></my-component>
|
<my-component></my-component>
|
||||||
@ -346,8 +360,10 @@ Initialize the WCC Tools dashboard.
|
|||||||
### DeesDemoWrapper
|
### DeesDemoWrapper
|
||||||
Component for wrapping demos with post-render logic.
|
Component for wrapping demos with post-render logic.
|
||||||
|
|
||||||
- `runAfterRender`: Function called after the wrapped element renders
|
- `runAfterRender`: Function called after the wrapped elements render
|
||||||
- Receives the first child element as parameter
|
- Receives the wrapper element itself, providing full DOM API access
|
||||||
|
- Use `wrapper.querySelector()` and `wrapper.querySelectorAll()` for element selection
|
||||||
|
- Access children via `wrapper.children` property
|
||||||
- Supports async operations
|
- Supports async operations
|
||||||
|
|
||||||
## Browser Support
|
## Browser Support
|
||||||
|
@ -34,11 +34,11 @@ The properties panel has timing issues detecting rendered elements because:
|
|||||||
## Created DeesDemoWrapper Component
|
## Created DeesDemoWrapper Component
|
||||||
- Location: ts_demotools/demotools.ts
|
- Location: ts_demotools/demotools.ts
|
||||||
- Allows wrapping demo elements with post-render functionality
|
- Allows wrapping demo elements with post-render functionality
|
||||||
- Provides runAfterRender callback that receives the rendered element
|
- Provides runAfterRender callback that receives ALL slotted elements as HTMLCollection
|
||||||
- Uses display: contents to not affect layout
|
- Uses display: contents to not affect layout
|
||||||
- Handles timing automatically with 50ms delay after firstUpdated
|
- Handles timing automatically with 50ms delay after firstUpdated
|
||||||
- Supports both sync and async callbacks
|
- Supports both sync and async callbacks
|
||||||
- Exports available at @design.estate/dees-wcctools/demoTools
|
- Exports available at @design.estate/dees-wcctools/demotools (lowercase)
|
||||||
|
|
||||||
# Documentation Update (COMPLETED)
|
# Documentation Update (COMPLETED)
|
||||||
|
|
||||||
@ -51,3 +51,50 @@ The properties panel has timing issues detecting rendered elements because:
|
|||||||
- API reference
|
- API reference
|
||||||
- Browser support information
|
- Browser support information
|
||||||
- Complete examples for all major features
|
- Complete examples for all major features
|
||||||
|
|
||||||
|
# Enhanced DemoWrapper (COMPLETED)
|
||||||
|
|
||||||
|
## Modified runAfterRender callback:
|
||||||
|
- Now receives the wrapper element itself instead of just children
|
||||||
|
- Provides full DOM API access (querySelector, querySelectorAll, etc.)
|
||||||
|
- querySelector works on slotted content (light DOM children)
|
||||||
|
- Access children via wrapper.children property
|
||||||
|
- Updated documentation with correct import path (lowercase 'demotools')
|
||||||
|
- Examples show how to use querySelector for powerful element selection
|
||||||
|
- Added clarifying comment about querySelector working on slotted content
|
||||||
|
|
||||||
|
## Fixed Properties Panel Compatibility:
|
||||||
|
- Made element search generic - works with any container elements
|
||||||
|
- Searches both light DOM and shadow DOM recursively
|
||||||
|
- Improved error handling to prevent breaking the update cycle
|
||||||
|
- Errors in one property don't prevent others from rendering
|
||||||
|
- Detection continues working even after errors occur
|
||||||
|
- Maintains compatibility with all element structures
|
||||||
|
|
||||||
|
# Test Elements Created (COMPLETED)
|
||||||
|
|
||||||
|
## Created comprehensive test elements:
|
||||||
|
1. **test-noprops** - Element with no @property decorators
|
||||||
|
2. **test-complextypes** - Element with arrays, objects, dates, and complex nested data
|
||||||
|
3. **test-withwrapper** - Element that uses dees-demowrapper in its demo
|
||||||
|
4. **test-edgecases** - Element with edge cases (null, undefined, NaN, Infinity, circular refs)
|
||||||
|
5. **test-nested** - Element with deeply nested structure to test recursive search
|
||||||
|
|
||||||
|
These test various scenarios:
|
||||||
|
- Properties panel handling of elements without properties
|
||||||
|
- Complex data type display and editing
|
||||||
|
- Element detection inside dees-demowrapper
|
||||||
|
- Error handling for problematic values
|
||||||
|
- Deep nesting and shadow DOM traversal
|
||||||
|
|
||||||
|
# Fixed Demo Value Overwriting (COMPLETED)
|
||||||
|
|
||||||
|
## Issue:
|
||||||
|
Properties panel was overwriting values set by demo functions
|
||||||
|
|
||||||
|
## Solution:
|
||||||
|
1. Changed from attribute binding (`value=`) to property binding (`.value=`)
|
||||||
|
2. This prevents browser from firing input events during initialization
|
||||||
|
3. Added proper number parsing for number inputs
|
||||||
|
4. Increased initial wait to 200ms for demo wrappers to complete
|
||||||
|
5. Simplified select element handling to use property binding
|
@ -1 +1,6 @@
|
|||||||
export * from './test-demoelement.js';
|
export * from './test-demoelement.js';
|
||||||
|
export * from './test-noprops.js';
|
||||||
|
export * from './test-complextypes.js';
|
||||||
|
export * from './test-withwrapper.js';
|
||||||
|
export * from './test-edgecases.js';
|
||||||
|
export * from './test-nested.js';
|
||||||
|
137
test/elements/test-complextypes.ts
Normal file
137
test/elements/test-complextypes.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
interface IComplexData {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
tags: string[];
|
||||||
|
metadata: {
|
||||||
|
created: Date;
|
||||||
|
modified: Date;
|
||||||
|
author: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('test-complextypes')
|
||||||
|
export class TestComplexTypes extends DeesElement {
|
||||||
|
public static demo = () => html`
|
||||||
|
<test-complextypes
|
||||||
|
.complexData=${{
|
||||||
|
name: 'Test User',
|
||||||
|
age: 25,
|
||||||
|
tags: ['developer', 'designer'],
|
||||||
|
metadata: {
|
||||||
|
created: new Date(),
|
||||||
|
modified: new Date(),
|
||||||
|
author: 'System'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
></test-complextypes>
|
||||||
|
`;
|
||||||
|
|
||||||
|
@property({ type: Array })
|
||||||
|
public stringArray: string[] = ['apple', 'banana', 'cherry'];
|
||||||
|
|
||||||
|
@property({ type: Array })
|
||||||
|
public numberArray: number[] = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public complexData: IComplexData = {
|
||||||
|
name: 'Default Name',
|
||||||
|
age: 0,
|
||||||
|
tags: [],
|
||||||
|
metadata: {
|
||||||
|
created: new Date(),
|
||||||
|
modified: new Date(),
|
||||||
|
author: 'Unknown'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@property({ type: Object })
|
||||||
|
public simpleObject = {
|
||||||
|
key1: 'value1',
|
||||||
|
key2: 'value2',
|
||||||
|
key3: 123
|
||||||
|
};
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public functionProperty = () => {
|
||||||
|
console.log('This is a function property');
|
||||||
|
};
|
||||||
|
|
||||||
|
@property({ type: Date })
|
||||||
|
public dateProperty = new Date();
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.section {
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 10px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
color: #666;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">String Array:</span>
|
||||||
|
<span class="value">${this.stringArray.join(', ')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Number Array:</span>
|
||||||
|
<span class="value">${this.numberArray.join(', ')}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Complex Data:</span>
|
||||||
|
<pre>${JSON.stringify(this.complexData, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Simple Object:</span>
|
||||||
|
<pre>${JSON.stringify(this.simpleObject, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Date Property:</span>
|
||||||
|
<span class="value">${this.dateProperty.toLocaleString()}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<span class="label">Function Property:</span>
|
||||||
|
<span class="value">${typeof this.functionProperty}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
195
test/elements/test-edgecases.ts
Normal file
195
test/elements/test-edgecases.ts
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
@customElement('test-edgecases')
|
||||||
|
export class TestEdgeCases extends DeesElement {
|
||||||
|
public static demo = () => html`<test-edgecases></test-edgecases>`;
|
||||||
|
|
||||||
|
// Property with null value
|
||||||
|
@property({ type: String })
|
||||||
|
public nullableString: string | null = null;
|
||||||
|
|
||||||
|
// Property with undefined value
|
||||||
|
@property({ type: Number })
|
||||||
|
public undefinedNumber: number | undefined = undefined;
|
||||||
|
|
||||||
|
// Very long string
|
||||||
|
@property({ type: String })
|
||||||
|
public longString: string = 'Lorem ipsum '.repeat(50);
|
||||||
|
|
||||||
|
// Property with special characters
|
||||||
|
@property({ type: String })
|
||||||
|
public specialChars: string = '!@#$%^&*()_+-=[]{}|;\':",./<>?`~';
|
||||||
|
|
||||||
|
// Property that could cause rendering issues
|
||||||
|
@property({ type: String })
|
||||||
|
public htmlString: string = '<script>alert("test")</script><b>Bold text</b>';
|
||||||
|
|
||||||
|
// Numeric edge cases
|
||||||
|
@property({ type: Number })
|
||||||
|
public infinityNumber: number = Infinity;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public nanNumber: number = NaN;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public veryLargeNumber: number = Number.MAX_SAFE_INTEGER;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public verySmallNumber: number = Number.MIN_SAFE_INTEGER;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public floatNumber: number = 3.14159265359;
|
||||||
|
|
||||||
|
// Boolean-like values
|
||||||
|
@property({ type: String })
|
||||||
|
public booleanString: string = 'false';
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public booleanNumber: number = 0;
|
||||||
|
|
||||||
|
// Empty values
|
||||||
|
@property({ type: String })
|
||||||
|
public emptyString: string = '';
|
||||||
|
|
||||||
|
@property({ type: Array })
|
||||||
|
public emptyArray: any[] = [];
|
||||||
|
|
||||||
|
@property({ type: Object })
|
||||||
|
public emptyObject: {} = {};
|
||||||
|
|
||||||
|
// Circular reference (should not break properties panel)
|
||||||
|
@property({ attribute: false })
|
||||||
|
public circularRef: any = (() => {
|
||||||
|
const obj: any = { name: 'circular' };
|
||||||
|
obj.self = obj;
|
||||||
|
return obj;
|
||||||
|
})();
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
background: #fff3e0;
|
||||||
|
border: 2px solid #ff9800;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
background: #ffe0b2;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #e65100;
|
||||||
|
}
|
||||||
|
.property {
|
||||||
|
margin: 5px 0;
|
||||||
|
padding: 5px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 2px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #f57c00;
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.special {
|
||||||
|
background: #ffccbc;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
private formatValue(value: any): string {
|
||||||
|
if (value === null) return 'null';
|
||||||
|
if (value === undefined) return 'undefined';
|
||||||
|
if (value === Infinity) return 'Infinity';
|
||||||
|
if (Number.isNaN(value)) return 'NaN';
|
||||||
|
if (typeof value === 'string' && value.length > 50) {
|
||||||
|
return value.substring(0, 50) + '...';
|
||||||
|
}
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
try {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
} catch (e) {
|
||||||
|
return '[Circular Reference]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="warning">
|
||||||
|
⚠️ This element tests edge cases and problematic values
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Nullable String:</span>
|
||||||
|
<span class="value special">${this.formatValue(this.nullableString)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Undefined Number:</span>
|
||||||
|
<span class="value special">${this.formatValue(this.undefinedNumber)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Long String:</span>
|
||||||
|
<span class="value">${this.formatValue(this.longString)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Special Characters:</span>
|
||||||
|
<span class="value">${this.specialChars}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">HTML String (escaped):</span>
|
||||||
|
<span class="value">${this.htmlString}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Infinity:</span>
|
||||||
|
<span class="value special">${this.formatValue(this.infinityNumber)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">NaN:</span>
|
||||||
|
<span class="value special">${this.formatValue(this.nanNumber)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Very Large Number:</span>
|
||||||
|
<span class="value">${this.veryLargeNumber}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Float Number:</span>
|
||||||
|
<span class="value">${this.floatNumber}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Empty String:</span>
|
||||||
|
<span class="value special">[empty]</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property">
|
||||||
|
<span class="label">Circular Reference:</span>
|
||||||
|
<span class="value special">${this.formatValue(this.circularRef)}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
127
test/elements/test-nested.ts
Normal file
127
test/elements/test-nested.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
// Helper component for nesting
|
||||||
|
@customElement('test-nested-wrapper')
|
||||||
|
class TestNestedWrapper extends DeesElement {
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div style="border: 1px dashed #ccc; padding: 10px; margin: 5px;">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The actual test element deeply nested
|
||||||
|
@customElement('test-nested-target')
|
||||||
|
class TestNestedTarget extends DeesElement {
|
||||||
|
@property({ type: String })
|
||||||
|
public message: string = 'I am deeply nested!';
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public depth: number = 0;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public found: boolean = false;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 15px;
|
||||||
|
background: #e1f5fe;
|
||||||
|
border: 2px solid #0288d1;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
font-family: monospace;
|
||||||
|
color: #01579b;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="info">
|
||||||
|
<strong>Nested Target Element</strong><br>
|
||||||
|
Message: ${this.message}<br>
|
||||||
|
Depth: ${this.depth}<br>
|
||||||
|
Found by properties panel: ${this.found ? '✅' : '❌'}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('test-nested')
|
||||||
|
export class TestNested extends DeesElement {
|
||||||
|
public static demo = () => html`
|
||||||
|
<test-nested></test-nested>
|
||||||
|
`;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public testId: string = 'nested-test';
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 2px solid #999;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.explanation {
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.structure {
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="explanation">
|
||||||
|
<h3>Nested Structure Test</h3>
|
||||||
|
<p>The actual element with properties is nested deep inside multiple layers:</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="structure">
|
||||||
|
<test-nested-wrapper>
|
||||||
|
<div style="padding: 10px; background: #ffe;">
|
||||||
|
<test-nested-wrapper>
|
||||||
|
<div style="padding: 10px; background: #efe;">
|
||||||
|
<test-nested-wrapper>
|
||||||
|
<div style="padding: 10px; background: #eef;">
|
||||||
|
<!-- The target element is here, 3 levels deep -->
|
||||||
|
<test-nested-target
|
||||||
|
.message=${'Found me at depth 3!'}
|
||||||
|
.depth=${3}
|
||||||
|
></test-nested-target>
|
||||||
|
</div>
|
||||||
|
</test-nested-wrapper>
|
||||||
|
</div>
|
||||||
|
</test-nested-wrapper>
|
||||||
|
</div>
|
||||||
|
</test-nested-wrapper>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 10px; font-style: italic; color: #666;">
|
||||||
|
Properties panel should find the test-nested-target element despite the deep nesting.
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
37
test/elements/test-noprops.ts
Normal file
37
test/elements/test-noprops.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
@customElement('test-noprops')
|
||||||
|
export class TestNoProps extends DeesElement {
|
||||||
|
public static demo = () => html`<test-noprops></test-noprops>`;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
font-family: monospace;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="message">
|
||||||
|
This element has no @property decorators.
|
||||||
|
Properties panel should handle this gracefully.
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
111
test/elements/test-withwrapper.ts
Normal file
111
test/elements/test-withwrapper.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
// Import from local demotools
|
||||||
|
import '../../ts_demotools/demotools.js';
|
||||||
|
|
||||||
|
@customElement('test-withwrapper')
|
||||||
|
export class TestWithWrapper extends DeesElement {
|
||||||
|
public static demo = () => html`
|
||||||
|
<dees-demowrapper .runAfterRender=${async (wrapper) => {
|
||||||
|
console.log('DemoWrapper: Found wrapper element', wrapper);
|
||||||
|
|
||||||
|
const testElement = wrapper.querySelector('test-withwrapper');
|
||||||
|
if (testElement) {
|
||||||
|
console.log('DemoWrapper: Found test-withwrapper element');
|
||||||
|
testElement.dynamicValue = 'Set by demo wrapper!';
|
||||||
|
testElement.counter = 100;
|
||||||
|
|
||||||
|
// Test querySelector functionality
|
||||||
|
const innerDiv = wrapper.querySelector('.inner-content');
|
||||||
|
console.log('DemoWrapper: Found inner div:', innerDiv);
|
||||||
|
|
||||||
|
// Test querySelectorAll
|
||||||
|
const allButtons = wrapper.querySelectorAll('button');
|
||||||
|
console.log(`DemoWrapper: Found ${allButtons.length} buttons`);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<test-withwrapper></test-withwrapper>
|
||||||
|
<div style="margin-top: 10px; padding: 10px; background: #e0e0e0;">
|
||||||
|
This div is also inside the wrapper
|
||||||
|
</div>
|
||||||
|
</dees-demowrapper>
|
||||||
|
`;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public dynamicValue: string = 'Initial value';
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
public counter: number = 0;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public isActive: boolean = false;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
background: #e8f5e9;
|
||||||
|
border: 2px solid #4caf50;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.wrapper-info {
|
||||||
|
background: #c8e6c9;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.inner-content {
|
||||||
|
background: white;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background: #4caf50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background: #45a049;
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="wrapper-info">
|
||||||
|
This element is wrapped with dees-demowrapper in its demo
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inner-content">
|
||||||
|
<h3>Dynamic Value: ${this.dynamicValue}</h3>
|
||||||
|
<p>Counter: ${this.counter}</p>
|
||||||
|
<p>Active: ${this.isActive ? 'Yes' : 'No'}</p>
|
||||||
|
|
||||||
|
<button @click=${() => this.counter++}>Increment</button>
|
||||||
|
<button @click=${() => this.isActive = !this.isActive}>Toggle Active</button>
|
||||||
|
<button @click=${() => this.dynamicValue = 'Clicked!'}>Change Value</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status">
|
||||||
|
Properties panel should detect this element inside the wrapper
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { DeesElement, customElement, html, css, property, type TemplateResult }
|
|||||||
@customElement('dees-demowrapper')
|
@customElement('dees-demowrapper')
|
||||||
export class DeesDemoWrapper extends DeesElement {
|
export class DeesDemoWrapper extends DeesElement {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public runAfterRender: (element: HTMLElement) => void | Promise<void>;
|
public runAfterRender: (wrapperElement: DeesDemoWrapper) => void | Promise<void>;
|
||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
css`
|
css`
|
||||||
@ -25,14 +25,13 @@ export class DeesDemoWrapper extends DeesElement {
|
|||||||
// Wait a bit for slotted content to render
|
// Wait a bit for slotted content to render
|
||||||
await new Promise(resolve => setTimeout(resolve, 50));
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
|
||||||
// Find the first element child (excluding text nodes)
|
// Check if there are slotted elements and runAfterRender is defined
|
||||||
const slottedElements = this.children;
|
if (this.children.length > 0 && this.runAfterRender) {
|
||||||
if (slottedElements.length > 0 && this.runAfterRender) {
|
// Call the runAfterRender function with the wrapper element itself
|
||||||
const firstElement = slottedElements[0] as HTMLElement;
|
// Note: querySelector/querySelectorAll will work on slotted content
|
||||||
|
// because slotted elements remain in the light DOM as children
|
||||||
// Call the runAfterRender function with the element
|
|
||||||
try {
|
try {
|
||||||
await this.runAfterRender(firstElement);
|
await this.runAfterRender(this);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in runAfterRender:', error);
|
console.error('Error in runAfterRender:', error);
|
||||||
}
|
}
|
||||||
|
@ -229,23 +229,28 @@ export class WccProperties extends DeesElement {
|
|||||||
private async findElementRecursively(container: Element, elementClass: any, maxDepth: number = 5): Promise<HTMLElement | null> {
|
private async findElementRecursively(container: Element, elementClass: any, maxDepth: number = 5): Promise<HTMLElement | null> {
|
||||||
if (maxDepth <= 0) return null;
|
if (maxDepth <= 0) return null;
|
||||||
|
|
||||||
// Check direct children
|
try {
|
||||||
for (const child of Array.from(container.children)) {
|
// Check direct children
|
||||||
if (child instanceof elementClass) {
|
for (const child of Array.from(container.children)) {
|
||||||
return child as HTMLElement;
|
if (child instanceof elementClass) {
|
||||||
|
return child as HTMLElement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check shadow roots of children
|
// Search in all children recursively
|
||||||
for (const child of Array.from(container.children)) {
|
for (const child of Array.from(container.children)) {
|
||||||
if (child.shadowRoot) {
|
// First, always check the light DOM children
|
||||||
const found = await this.findElementRecursively(child.shadowRoot as any, elementClass, maxDepth - 1);
|
const found = await this.findElementRecursively(child, elementClass, maxDepth - 1);
|
||||||
if (found) return found;
|
if (found) return found;
|
||||||
}
|
|
||||||
|
|
||||||
// Also check nested children
|
// Also check shadow root if it exists
|
||||||
const found = await this.findElementRecursively(child, elementClass, maxDepth - 1);
|
if (child.shadowRoot) {
|
||||||
if (found) return found;
|
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;
|
return null;
|
||||||
@ -254,6 +259,9 @@ export class WccProperties extends DeesElement {
|
|||||||
public async createProperties() {
|
public async createProperties() {
|
||||||
console.log('creating properties for:');
|
console.log('creating properties for:');
|
||||||
console.log(this.selectedItem);
|
console.log(this.selectedItem);
|
||||||
|
|
||||||
|
// Clear any previous warnings
|
||||||
|
this.warning = null;
|
||||||
const isEnumeration = (propertyArg): boolean => {
|
const isEnumeration = (propertyArg): boolean => {
|
||||||
const keys = Object.keys(propertyArg.type);
|
const keys = Object.keys(propertyArg.type);
|
||||||
const values = [];
|
const values = [];
|
||||||
@ -301,8 +309,8 @@ export class WccProperties extends DeesElement {
|
|||||||
console.log(anonItem.elementProperties);
|
console.log(anonItem.elementProperties);
|
||||||
const wccFrame = await this.dashboardRef.wccFrame;
|
const wccFrame = await this.dashboardRef.wccFrame;
|
||||||
|
|
||||||
// Wait for render to complete
|
// Wait for render to complete and any demo wrappers to run
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
// Try to find the element with recursive search
|
// Try to find the element with recursive search
|
||||||
const viewport = await wccFrame.getViewportElement();
|
const viewport = await wccFrame.getViewportElement();
|
||||||
@ -315,15 +323,20 @@ export class WccProperties extends DeesElement {
|
|||||||
let retries = 0;
|
let retries = 0;
|
||||||
while (!firstFoundInstantiatedElement && retries < 5) {
|
while (!firstFoundInstantiatedElement && retries < 5) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 200));
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
firstFoundInstantiatedElement = await this.findElementRecursively(
|
try {
|
||||||
viewport,
|
firstFoundInstantiatedElement = await this.findElementRecursively(
|
||||||
this.selectedItem as any
|
viewport,
|
||||||
);
|
this.selectedItem as any
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during element search retry:', error);
|
||||||
|
}
|
||||||
retries++;
|
retries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!firstFoundInstantiatedElement) {
|
if (!firstFoundInstantiatedElement) {
|
||||||
this.warning = `no first instantiated element found for >>${anonItem.name}<< after ${retries} retries`;
|
this.warning = `no first instantiated element found for >>${anonItem.name}<< after ${retries} retries`;
|
||||||
|
this.propertyContent = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const classProperties: Map<string, any> = anonItem.elementProperties;
|
const classProperties: Map<string, any> = anonItem.elementProperties;
|
||||||
@ -337,9 +350,10 @@ export class WccProperties extends DeesElement {
|
|||||||
if (key === 'goBright' || key === 'domtools') {
|
if (key === 'goBright' || key === 'domtools') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const property = classProperties.get(key);
|
try {
|
||||||
const propertyTypeString = await determinePropertyType(property);
|
const property = classProperties.get(key);
|
||||||
propertyArray.push(
|
const propertyTypeString = await determinePropertyType(property);
|
||||||
|
propertyArray.push(
|
||||||
html`
|
html`
|
||||||
<div class="property">
|
<div class="property">
|
||||||
${key} / ${propertyTypeString}<br />
|
${key} / ${propertyTypeString}<br />
|
||||||
@ -356,7 +370,7 @@ export class WccProperties extends DeesElement {
|
|||||||
case 'String':
|
case 'String':
|
||||||
return html`<input
|
return html`<input
|
||||||
type="text"
|
type="text"
|
||||||
value=${firstFoundInstantiatedElement[key]}
|
.value=${firstFoundInstantiatedElement[key] || ''}
|
||||||
@input="${(eventArg: any) => {
|
@input="${(eventArg: any) => {
|
||||||
firstFoundInstantiatedElement[key] = eventArg.target.value;
|
firstFoundInstantiatedElement[key] = eventArg.target.value;
|
||||||
}}"
|
}}"
|
||||||
@ -364,14 +378,15 @@ export class WccProperties extends DeesElement {
|
|||||||
case 'Number':
|
case 'Number':
|
||||||
return html`<input
|
return html`<input
|
||||||
type="number"
|
type="number"
|
||||||
value=${firstFoundInstantiatedElement[key]}
|
.value=${firstFoundInstantiatedElement[key] ?? ''}
|
||||||
@input="${(eventArg: any) => {
|
@input="${(eventArg: any) => {
|
||||||
firstFoundInstantiatedElement[key] = eventArg.target.value;
|
firstFoundInstantiatedElement[key] = parseFloat(eventArg.target.value) || 0;
|
||||||
}}"
|
}}"
|
||||||
/>`;
|
/>`;
|
||||||
case 'Enum':
|
case 'Enum':
|
||||||
const enumValues: any[] = getEnumValues(property);
|
const enumValues: any[] = getEnumValues(property);
|
||||||
return html`<select
|
return html`<select
|
||||||
|
.value=${firstFoundInstantiatedElement[key] || ''}
|
||||||
@change="${(eventArg: any) => {
|
@change="${(eventArg: any) => {
|
||||||
firstFoundInstantiatedElement[key] = eventArg.target.value;
|
firstFoundInstantiatedElement[key] = eventArg.target.value;
|
||||||
}}"
|
}}"
|
||||||
@ -379,8 +394,7 @@ export class WccProperties extends DeesElement {
|
|||||||
${enumValues.map((valueArg) => {
|
${enumValues.map((valueArg) => {
|
||||||
return html`
|
return html`
|
||||||
<option
|
<option
|
||||||
?selected=${valueArg === firstFoundInstantiatedElement[key] ? true : false}
|
value="${valueArg}"
|
||||||
name="${valueArg}"
|
|
||||||
>
|
>
|
||||||
${valueArg}
|
${valueArg}
|
||||||
</option>
|
</option>
|
||||||
@ -392,6 +406,10 @@ export class WccProperties extends DeesElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error processing property ${key}:`, error);
|
||||||
|
// Continue with next property even if this one fails
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.propertyContent = propertyArray;
|
this.propertyContent = propertyArray;
|
||||||
} else {
|
} else {
|
||||||
@ -413,7 +431,14 @@ export class WccProperties extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async scheduleUpdate() {
|
public async scheduleUpdate() {
|
||||||
await this.createProperties();
|
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();
|
super.scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user