3.9 KiB
3.9 KiB
@design.estate/dees-wcctools/demotools
🧪 Demo Wrapper Utilities — Enhanced testing tools for web component demos
Overview
The demotools module provides dees-demowrapper, a utility component for executing post-render logic in component demos. Perfect for simulating user interactions, setting up test data, or validating component state.
Installation
This module is included with @design.estate/dees-wcctools:
pnpm add -D @design.estate/dees-wcctools
Usage
Import the demotools subpath:
import '@design.estate/dees-wcctools/demotools';
DeesDemoWrapper
A wrapper component that executes a callback after its slotted content renders.
Properties
| Property | Type | Description |
|---|---|---|
runAfterRender |
(wrapper: DeesDemoWrapper) => void | Promise<void> |
Callback executed after content renders |
Example: Basic Usage
import { html } from 'lit';
import '@design.estate/dees-wcctools/demotools';
public static demo = () => html`
<dees-demowrapper .runAfterRender=${(wrapper) => {
const button = wrapper.querySelector('my-button');
console.log('Button found:', button);
}}>
<my-button>Click Me</my-button>
</dees-demowrapper>
`;
Example: Async Operations
public static demo = () => html`
<dees-demowrapper .runAfterRender=${async (wrapper) => {
const form = wrapper.querySelector('my-form');
// Wait for component initialization
await form.updateComplete;
// Simulate user input
form.values = { name: 'Test User', email: 'test@example.com' };
// Trigger validation
await form.validate();
console.log('Form state:', form.isValid);
}}>
<my-form></my-form>
</dees-demowrapper>
`;
Example: Multiple Elements
public static demo = () => html`
<dees-demowrapper .runAfterRender=${(wrapper) => {
// Find all cards
const cards = wrapper.querySelectorAll('my-card');
console.log(`Found ${cards.length} cards`);
// Access by index
Array.from(wrapper.children).forEach((child, i) => {
console.log(`Child ${i}:`, child.tagName);
});
// Add event listeners
wrapper.querySelectorAll('button').forEach(btn => {
btn.addEventListener('click', () => console.log('Clicked!'));
});
}}>
<my-card title="Card 1"></my-card>
<my-card title="Card 2"></my-card>
<my-card title="Card 3"></my-card>
</dees-demowrapper>
`;
Example: Component State Manipulation
public static demo = () => html`
<dees-demowrapper .runAfterRender=${async (wrapper) => {
const tabs = wrapper.querySelector('my-tabs');
// Programmatically switch tabs
tabs.activeTab = 'settings';
await tabs.updateComplete;
// Verify content updated
const content = tabs.shadowRoot.querySelector('.tab-content');
console.log('Active content:', content.textContent);
}}>
<my-tabs>
<div slot="home">Home Content</div>
<div slot="settings">Settings Content</div>
</my-tabs>
</dees-demowrapper>
`;
How It Works
- The wrapper renders its slot content immediately
- After a brief delay (50ms) to allow slotted content to initialize
- The
runAfterRendercallback is invoked with the wrapper element - You have full DOM API access to query and manipulate children
Key Features
- 📦 Light DOM Access — Slotted elements remain accessible via standard DOM APIs
- ⏱️ Async Support — Return a Promise for async operations
- 🎯 Full DOM API — Use
querySelector,querySelectorAll,children, etc. - 🛡️ Error Handling — Errors in callbacks are caught and logged
CSS Behavior
The wrapper uses display: contents so it doesn't affect layout:
:host {
display: contents;
}
This means the wrapper is "invisible" in the layout — its children render as if they were direct children of the wrapper's parent.