148 lines
3.9 KiB
Markdown
148 lines
3.9 KiB
Markdown
# @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`:
|
|
|
|
```bash
|
|
pnpm add -D @design.estate/dees-wcctools
|
|
```
|
|
|
|
## Usage
|
|
|
|
Import the demotools subpath:
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
1. The wrapper renders its slot content immediately
|
|
2. After a brief delay (50ms) to allow slotted content to initialize
|
|
3. The `runAfterRender` callback is invoked with the wrapper element
|
|
4. 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:
|
|
|
|
```css
|
|
: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.
|