@design.estate/wcctools 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.smartconfig.json +65 -0
- package/changelog.md +414 -0
- package/dist_bundle/bundle.js +92419 -0
- package/dist_bundle/bundle.js.map +1 -0
- package/dist_ts_web/00_commitinfo_data.d.ts +8 -0
- package/dist_ts_web/00_commitinfo_data.js +9 -0
- package/dist_ts_web/elements/wcc-contextmenu.d.ts +41 -0
- package/dist_ts_web/elements/wcc-contextmenu.js +329 -0
- package/dist_ts_web/elements/wcc-dashboard.d.ts +119 -0
- package/dist_ts_web/elements/wcc-dashboard.js +700 -0
- package/dist_ts_web/elements/wcc-frame.d.ts +22 -0
- package/dist_ts_web/elements/wcc-frame.js +256 -0
- package/dist_ts_web/elements/wcc-properties.d.ts +43 -0
- package/dist_ts_web/elements/wcc-properties.js +1147 -0
- package/dist_ts_web/elements/wcc-record-button.d.ts +12 -0
- package/dist_ts_web/elements/wcc-record-button.js +165 -0
- package/dist_ts_web/elements/wcc-recording-panel.d.ts +44 -0
- package/dist_ts_web/elements/wcc-recording-panel.js +1103 -0
- package/dist_ts_web/elements/wcc-sidebar.d.ts +91 -0
- package/dist_ts_web/elements/wcc-sidebar.js +1497 -0
- package/dist_ts_web/elements/wcctools.helpers.d.ts +46 -0
- package/dist_ts_web/elements/wcctools.helpers.js +106 -0
- package/dist_ts_web/index.d.ts +18 -0
- package/dist_ts_web/index.js +30 -0
- package/dist_ts_web/pages/index.d.ts +1 -0
- package/dist_ts_web/pages/index.js +2 -0
- package/dist_ts_web/services/recorder.service.d.ts +55 -0
- package/dist_ts_web/services/recorder.service.js +353 -0
- package/dist_ts_web/wcctools.interfaces.d.ts +29 -0
- package/dist_ts_web/wcctools.interfaces.js +2 -0
- package/dist_ts_web/wcctools.plugins.d.ts +2 -0
- package/dist_ts_web/wcctools.plugins.js +3 -0
- package/license.md +19 -0
- package/package.json +64 -0
- package/readme.md +568 -0
- package/ts_web/00_commitinfo_data.ts +8 -0
- package/ts_web/elements/wcc-contextmenu.ts +291 -0
- package/ts_web/elements/wcc-dashboard.ts +672 -0
- package/ts_web/elements/wcc-frame.ts +189 -0
- package/ts_web/elements/wcc-properties.ts +1089 -0
- package/ts_web/elements/wcc-record-button.ts +108 -0
- package/ts_web/elements/wcc-recording-panel.ts +1010 -0
- package/ts_web/elements/wcc-sidebar.ts +1470 -0
- package/ts_web/elements/wcctools.helpers.ts +153 -0
- package/ts_web/index.ts +38 -0
- package/ts_web/pages/index.ts +1 -0
- package/ts_web/readme.md +177 -0
- package/ts_web/services/recorder.service.ts +451 -0
- package/ts_web/tspublish.json +3 -0
- package/ts_web/types/dom-mediacapture-stub/index.d.ts +12 -0
- package/ts_web/types/dom-mediacapture-stub/package.json +6 -0
- package/ts_web/types/dom-webcodecs-stub/index.d.ts +2 -0
- package/ts_web/types/dom-webcodecs-stub/package.json +6 -0
- package/ts_web/wcctools.interfaces.ts +31 -0
- package/ts_web/wcctools.plugins.ts +5 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { TemplateResult } from 'lit';
|
|
2
|
+
|
|
3
|
+
export type TTemplateFactory = () => TemplateResult | Promise<TemplateResult>;
|
|
4
|
+
|
|
5
|
+
/** Find the nearest matching instance through light DOM and open shadow roots. */
|
|
6
|
+
export const findElementInstance = <T extends HTMLElement>(
|
|
7
|
+
containerArg: Element | ShadowRoot,
|
|
8
|
+
elementClassArg: new (...args: any[]) => T,
|
|
9
|
+
): T | null => {
|
|
10
|
+
const pending = Array.from(containerArg.children);
|
|
11
|
+
for (let index = 0; index < pending.length; index++) {
|
|
12
|
+
const element = pending[index];
|
|
13
|
+
if (element instanceof elementClassArg) return element;
|
|
14
|
+
pending.push(...element.children);
|
|
15
|
+
if (element.shadowRoot) pending.push(...element.shadowRoot.children);
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Demo can be a single function or an array of functions
|
|
21
|
+
export type TDemoDefinition = TTemplateFactory | TTemplateFactory[];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* How a catalog export is treated in an elements section:
|
|
25
|
+
* - `demo`: a custom element class with a usable static `demo`; listed and navigable
|
|
26
|
+
* - `no-demo`: a registered custom element without a usable demo; listed under "Without demo"
|
|
27
|
+
* - `ignored`: anything else (helpers, constants, types at runtime, abstract base classes)
|
|
28
|
+
*/
|
|
29
|
+
export type TCatalogEntryKind = 'demo' | 'no-demo' | 'ignored';
|
|
30
|
+
|
|
31
|
+
/** The static surface wcctools reads from a catalog element class. */
|
|
32
|
+
export interface ICatalogElementConstructor extends CustomElementConstructor {
|
|
33
|
+
demo?: unknown;
|
|
34
|
+
demoGroups?: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A demo is one template factory or a non-empty array of template factories. */
|
|
38
|
+
export const isDemoDefinition = (demoArg: unknown): demoArg is TDemoDefinition => {
|
|
39
|
+
if (typeof demoArg === 'function') {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return Array.isArray(demoArg)
|
|
43
|
+
&& demoArg.length > 0
|
|
44
|
+
&& demoArg.every((factoryArg) => typeof factoryArg === 'function');
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** True for classes that extend HTMLElement (registered or not). */
|
|
48
|
+
export const isElementConstructor = (itemArg: unknown): itemArg is ICatalogElementConstructor => {
|
|
49
|
+
return typeof HTMLElement !== 'undefined'
|
|
50
|
+
&& typeof itemArg === 'function'
|
|
51
|
+
&& itemArg.prototype instanceof HTMLElement;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** Classify one export of an elements section. */
|
|
55
|
+
export const classifyCatalogEntry = (itemArg: unknown): TCatalogEntryKind => {
|
|
56
|
+
if (!isElementConstructor(itemArg)) {
|
|
57
|
+
return 'ignored';
|
|
58
|
+
}
|
|
59
|
+
if (isDemoDefinition(itemArg.demo)) {
|
|
60
|
+
return 'demo';
|
|
61
|
+
}
|
|
62
|
+
return customElements.getName(itemArg) ? 'no-demo' : 'ignored';
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** The tag name an element class is registered under, if any. */
|
|
66
|
+
export const getElementTagName = (itemArg: unknown): string | null => {
|
|
67
|
+
return isElementConstructor(itemArg) ? customElements.getName(itemArg) : null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** The demo groups an element declares, normalized to an array. */
|
|
71
|
+
export const getElementDemoGroups = (itemArg: unknown): string[] => {
|
|
72
|
+
if (!isElementConstructor(itemArg)) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const groups = itemArg.demoGroups;
|
|
76
|
+
const list = Array.isArray(groups) ? groups : [groups];
|
|
77
|
+
return list.filter((groupArg): groupArg is string => typeof groupArg === 'string' && groupArg.length > 0);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export type TPropertyType = 'String' | 'Number' | 'Boolean' | 'Object' | 'Enum' | 'Array';
|
|
81
|
+
|
|
82
|
+
export interface IReactivePropertyDeclaration {
|
|
83
|
+
state?: boolean;
|
|
84
|
+
type?: unknown;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const isEnumerationType = (typeArg: unknown): boolean => {
|
|
88
|
+
if (!typeArg || typeof typeArg !== 'object' || Array.isArray(typeArg)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const values = Object.values(typeArg);
|
|
93
|
+
return values.length > 0 && values.every((valueArg) =>
|
|
94
|
+
typeof valueArg === 'string' || typeof valueArg === 'number'
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const determinePropertyType = (
|
|
99
|
+
propertyArg: IReactivePropertyDeclaration
|
|
100
|
+
): TPropertyType | null => {
|
|
101
|
+
if (!propertyArg || typeof propertyArg !== 'object' || propertyArg.state) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
switch (propertyArg.type) {
|
|
106
|
+
case String:
|
|
107
|
+
return 'String';
|
|
108
|
+
case Number:
|
|
109
|
+
return 'Number';
|
|
110
|
+
case Boolean:
|
|
111
|
+
return 'Boolean';
|
|
112
|
+
case Object:
|
|
113
|
+
return 'Object';
|
|
114
|
+
case Array:
|
|
115
|
+
return 'Array';
|
|
116
|
+
default:
|
|
117
|
+
return isEnumerationType(propertyArg.type) ? 'Enum' : null;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const resolveTemplateFactory = async (
|
|
122
|
+
factoryArg: TTemplateFactory
|
|
123
|
+
): Promise<TemplateResult> => {
|
|
124
|
+
return await Promise.resolve(factoryArg());
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get the number of demos for an element
|
|
129
|
+
*/
|
|
130
|
+
export const getDemoCount = (demo: TDemoDefinition): number => {
|
|
131
|
+
if (Array.isArray(demo)) {
|
|
132
|
+
return demo.length;
|
|
133
|
+
}
|
|
134
|
+
return 1;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get a specific demo by index (0-based internally, displayed as 1-based)
|
|
139
|
+
*/
|
|
140
|
+
export const getDemoAtIndex = (demo: TDemoDefinition, index: number): TTemplateFactory | null => {
|
|
141
|
+
if (Array.isArray(demo)) {
|
|
142
|
+
return demo[index] ?? null;
|
|
143
|
+
}
|
|
144
|
+
// Single demo - only index 0 is valid
|
|
145
|
+
return index === 0 ? demo : null;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Check if an element has multiple demos
|
|
150
|
+
*/
|
|
151
|
+
export const hasMultipleDemos = (demo: TDemoDefinition): boolean => {
|
|
152
|
+
return Array.isArray(demo) && demo.length > 1;
|
|
153
|
+
};
|
package/ts_web/index.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { WccDashboard } from './elements/wcc-dashboard.js';
|
|
2
|
+
import type { IWccConfig, IWccSection } from './wcctools.interfaces.js';
|
|
3
|
+
|
|
4
|
+
// Export recording components and service
|
|
5
|
+
export { RecorderService, type IRecorderEvents, type IRecordingOptions, type TOutputFormat } from './services/recorder.service.js';
|
|
6
|
+
export { WccRecordButton } from './elements/wcc-record-button.js';
|
|
7
|
+
export { WccRecordingPanel } from './elements/wcc-recording-panel.js';
|
|
8
|
+
|
|
9
|
+
// Export types for external use
|
|
10
|
+
export type { IWccConfig, IWccSection } from './wcctools.interfaces.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Set up the WCC Tools dashboard:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* setupWccTools({
|
|
16
|
+
* sections: [
|
|
17
|
+
* { name: 'Elements', type: 'elements', items: elements },
|
|
18
|
+
* { name: 'Pages', type: 'pages', items: pages },
|
|
19
|
+
* ]
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
const setupWccTools = (config: IWccConfig) => {
|
|
24
|
+
let hasRun = false;
|
|
25
|
+
const runWccToolsSetup = async () => {
|
|
26
|
+
if (document.readyState === 'complete' && !hasRun) {
|
|
27
|
+
hasRun = true;
|
|
28
|
+
const wccTools = new WccDashboard(config);
|
|
29
|
+
document.querySelector('body').append(wccTools);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
document.addEventListener('readystatechange', runWccToolsSetup);
|
|
33
|
+
runWccToolsSetup();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
setupWccTools
|
|
38
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const page1 = null;
|
package/ts_web/readme.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# @design.estate/wcctools
|
|
2
|
+
|
|
3
|
+
🛠️ **Web Component Catalogue Tools** — The core dashboard and UI components for building interactive component catalogues
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This is the main module of `@design.estate/wcctools`, providing the complete dashboard experience for developing, testing, and documenting web components.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add -D @design.estate/wcctools
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Sections-based Configuration (Recommended)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { setupWccTools } from '@design.estate/wcctools';
|
|
21
|
+
import * as elements from './elements/index.js';
|
|
22
|
+
import * as views from './views/index.js';
|
|
23
|
+
import * as pages from './pages/index.js';
|
|
24
|
+
|
|
25
|
+
setupWccTools({
|
|
26
|
+
sections: [
|
|
27
|
+
{
|
|
28
|
+
name: 'Pages',
|
|
29
|
+
type: 'pages',
|
|
30
|
+
items: pages,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Views',
|
|
34
|
+
type: 'elements',
|
|
35
|
+
items: views,
|
|
36
|
+
icon: 'web',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Elements',
|
|
40
|
+
type: 'elements',
|
|
41
|
+
items: elements,
|
|
42
|
+
filter: (name) => !name.startsWith('internal-'),
|
|
43
|
+
sort: ([a], [b]) => a.localeCompare(b),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Migration from the Two-Argument Form
|
|
50
|
+
|
|
51
|
+
`setupWccTools(elements, pages)` is removed in 5.0.0; pass the same maps as `pages` and `elements` sections.
|
|
52
|
+
|
|
53
|
+
### What the Sidebar Lists
|
|
54
|
+
|
|
55
|
+
In an `elements` section, only classes extending `HTMLElement` with a static `demo` are listed and navigable. Registered custom elements without a demo appear in a collapsed, non-clickable **Without demo** group; every other export (helpers, constants, unregistered base classes) is ignored. Classification runs before the section's `filter` and `sort`. `pages` sections list template factories only. See the package readme for details and keyboard use.
|
|
56
|
+
|
|
57
|
+
## Exports
|
|
58
|
+
|
|
59
|
+
### Main Entry Point
|
|
60
|
+
|
|
61
|
+
| Export | Description |
|
|
62
|
+
|--------|-------------|
|
|
63
|
+
| `setupWccTools` | Initialize the component catalogue dashboard |
|
|
64
|
+
| `IWccConfig` | TypeScript interface for sections configuration |
|
|
65
|
+
| `IWccSection` | TypeScript interface for individual section |
|
|
66
|
+
|
|
67
|
+
### Recording Components
|
|
68
|
+
|
|
69
|
+
| Export | Description |
|
|
70
|
+
|--------|-------------|
|
|
71
|
+
| `RecorderService` | Service class for screen/viewport recording and MP4 conversion |
|
|
72
|
+
| `WccRecordButton` | Record button UI component |
|
|
73
|
+
| `WccRecordingPanel` | Recording options and preview panel |
|
|
74
|
+
| `IRecorderEvents` | TypeScript interface for recorder callbacks |
|
|
75
|
+
| `IRecordingOptions` | TypeScript interface for recording options |
|
|
76
|
+
| `TOutputFormat` | Type for output format selection (`'webm' \| 'mp4'`) |
|
|
77
|
+
|
|
78
|
+
## Section Configuration
|
|
79
|
+
|
|
80
|
+
| Property | Type | Description |
|
|
81
|
+
|----------|------|-------------|
|
|
82
|
+
| `name` | `string` | Display name for the section header |
|
|
83
|
+
| `type` | `'elements' \| 'pages'` | Rendering behavior |
|
|
84
|
+
| `items` | `Record<string, any>` | Element classes or page factories |
|
|
85
|
+
| `filter` | `(name, item) => boolean` | Optional filter function |
|
|
86
|
+
| `sort` | `([a, itemA], [b, itemB]) => number` | Optional sort function |
|
|
87
|
+
| `icon` | `string` | Material Symbols icon name |
|
|
88
|
+
| `collapsed` | `boolean` | Start section collapsed (default: false) |
|
|
89
|
+
|
|
90
|
+
## Internal Components
|
|
91
|
+
|
|
92
|
+
The module includes these internal web components:
|
|
93
|
+
|
|
94
|
+
| Component | Description |
|
|
95
|
+
|-----------|-------------|
|
|
96
|
+
| `wcc-dashboard` | Main dashboard container with routing |
|
|
97
|
+
| `wcc-sidebar` | Navigation sidebar with collapsible sections and search |
|
|
98
|
+
| `wcc-frame` | Responsive viewport with size controls |
|
|
99
|
+
| `wcc-properties` | Property panel with live editing |
|
|
100
|
+
| `wcc-record-button` | Recording state indicator button |
|
|
101
|
+
| `wcc-recording-panel` | Recording workflow UI with format selection |
|
|
102
|
+
|
|
103
|
+
## RecorderService API
|
|
104
|
+
|
|
105
|
+
For programmatic recording and MP4 conversion:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { RecorderService, type IRecorderEvents } from '@design.estate/wcctools';
|
|
109
|
+
|
|
110
|
+
const events: IRecorderEvents = {
|
|
111
|
+
onDurationUpdate: (duration) => console.log(`Recording: ${duration}s`),
|
|
112
|
+
onRecordingComplete: (blob) => saveBlob(blob),
|
|
113
|
+
onAudioLevelUpdate: (level) => updateMeter(level),
|
|
114
|
+
onError: (error) => console.error(error),
|
|
115
|
+
onStreamEnded: () => console.log('User stopped sharing'),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const recorder = new RecorderService(events);
|
|
119
|
+
|
|
120
|
+
// Load available microphones
|
|
121
|
+
const mics = await recorder.loadMicrophones(true);
|
|
122
|
+
|
|
123
|
+
// Start audio level monitoring
|
|
124
|
+
await recorder.startAudioMonitoring(mics[0].deviceId);
|
|
125
|
+
|
|
126
|
+
// Start recording (always captures as WebM internally at up to 60fps)
|
|
127
|
+
await recorder.startRecording({
|
|
128
|
+
mode: 'viewport',
|
|
129
|
+
audioDeviceId: mics[0].deviceId,
|
|
130
|
+
viewportElement: document.querySelector('.viewport'),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Stop recording
|
|
134
|
+
recorder.stopRecording();
|
|
135
|
+
|
|
136
|
+
// Convert to MP4 for universal playback (H.264 + AAC via WebCodecs)
|
|
137
|
+
const mp4Blob = await recorder.convertToMp4(recorder.recordedBlob);
|
|
138
|
+
|
|
139
|
+
// Or export trimmed video
|
|
140
|
+
const trimmedBlob = await recorder.exportTrimmedVideo(videoElement, startTime, endTime);
|
|
141
|
+
|
|
142
|
+
// Cleanup
|
|
143
|
+
recorder.dispose();
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Architecture
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
ts_web/
|
|
150
|
+
├── index.ts # Main exports
|
|
151
|
+
├── wcctools.interfaces.ts # Type definitions
|
|
152
|
+
├── types/
|
|
153
|
+
│ ├── dom-webcodecs-stub/ # TS6 compatibility shim
|
|
154
|
+
│ └── dom-mediacapture-stub/ # MediaCapture Transform types
|
|
155
|
+
├── elements/
|
|
156
|
+
│ ├── wcc-dashboard.ts # Root dashboard component
|
|
157
|
+
│ ├── wcc-sidebar.ts # Navigation sidebar
|
|
158
|
+
│ ├── wcc-frame.ts # Responsive viewport
|
|
159
|
+
│ ├── wcc-properties.ts # Property editing panel
|
|
160
|
+
│ ├── wcc-record-button.ts # Recording button
|
|
161
|
+
│ ├── wcc-recording-panel.ts # Recording options/preview
|
|
162
|
+
│ └── wcctools.helpers.ts # Shared utilities
|
|
163
|
+
├── services/
|
|
164
|
+
│ └── recorder.service.ts # MediaRecorder + mediabunny MP4 conversion
|
|
165
|
+
└── pages/
|
|
166
|
+
└── index.ts # Built-in pages
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Features
|
|
170
|
+
|
|
171
|
+
- 🎨 Interactive component preview
|
|
172
|
+
- 📂 Section-based sidebar with filtering, sorting & search (by name, tag, or group)
|
|
173
|
+
- 🔧 Real-time property editing with type detection
|
|
174
|
+
- 🌓 Theme switching (light/dark)
|
|
175
|
+
- 📱 Responsive viewport testing
|
|
176
|
+
- 🎬 Screen recording with MP4/WebM export, trimming, and audio
|
|
177
|
+
- 🔗 URL-based deep linking
|