11import type {
22 Attribute ,
33 CustomElementDeclaration ,
4- Declaration ,
54 Package ,
65 Slot ,
76} from 'custom-elements-manifest' ;
87
9- import { LitElement , css , html , type PropertyValues } from 'lit' ;
8+ import type {
9+ AttributeRenderer ,
10+ AttributeKnobInfo ,
11+ ContentKnobInfo ,
12+ ContentRenderer ,
13+ } from './lib/knobs.js' ;
14+
15+ import { LitElement , html , type PropertyValues } from 'lit' ;
1016import { customElement } from 'lit/decorators/custom-element.js' ;
1117import { property } from 'lit/decorators/property.js' ;
1218import { ifDefined } from 'lit/directives/if-defined.js' ;
1319
20+ import {
21+ isCustomElementDecl ,
22+ isCheckable ,
23+ isValue ,
24+ isAttributelessProperty ,
25+ dedent ,
26+ } from './lib/knobs.js' ;
27+
1428import 'zero-md' ;
1529
1630import './pft-html-editor.js' ;
1731
18- interface KnobInfo < E > {
19- element : E ;
20- knobId : string ;
21- }
22-
23- interface AttributeKnobInfo < E > extends KnobInfo < E > {
24- isBoolean : boolean ;
25- isEnum : boolean ;
26- isNullable : boolean ;
27- isNumber : boolean ;
28- isOptional : boolean ;
29- values : string [ ] ;
30- }
31-
32- type ContentKnobInfo < E > = KnobInfo < E > ;
33-
34- type KnobRenderer < T , E extends HTMLElement = HTMLElement > = (
35- this : PftElementKnobs < E > ,
36- member : T ,
37- info :
38- T extends Attribute ? AttributeKnobInfo < E >
39- : T extends Slot [ ] ? ContentKnobInfo < E >
40- : KnobInfo < E > ,
41- ) => unknown ;
42-
43- export type AttributeRenderer < E extends HTMLElement > = KnobRenderer < Attribute , E > ;
44- export type ContentRenderer < E extends HTMLElement > = KnobRenderer < Slot [ ] , E > ;
45-
46- const isCheckable = ( el : HTMLElement ) : el is HTMLElement & { checked : boolean } =>
47- 'checked' in el ;
48-
49- const isValue = ( el : HTMLElement ) : el is HTMLElement & { value : string } =>
50- 'value' in el ;
51-
52- const isCustomElementDecl = ( decl : Declaration ) : decl is CustomElementDeclaration =>
53- 'customElement' in decl ;
32+ import style from './pft-element-knobs.css' ;
5433
5534@customElement ( 'pft-element-knobs' )
5635export class PftElementKnobs < T extends HTMLElement > extends LitElement {
57- static styles = [
58- css `
59- #element {
60- padding: 1em;
61- }
62-
63- #attributes,
64- dl#slot-descriptions {
65- display: grid;
66- gap: 8px;
67- grid-template-columns: max-content auto;
68- & dd {
69- margin-inline-start: 0;
70- }
71- & > h2 {
72- grid-column: -1/1;
73- }
74- }
75- ` ,
76- ] ;
36+ static styles = [ style ] ;
7737
7838 @property ( ) tag ?: string ;
7939
@@ -119,7 +79,7 @@ export class PftElementKnobs<T extends HTMLElement> extends LitElement {
11979 try {
12080 this . manifest = JSON . parse ( script . textContent ?? '' ) ;
12181 } catch {
122- null ;
82+ void 0 ;
12383 }
12484 }
12585 if ( this . #template && this . tag ) {
@@ -165,7 +125,7 @@ export class PftElementKnobs<T extends HTMLElement> extends LitElement {
165125 < template >
166126 < link rel ="stylesheet " href ="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown-dark.min.css ">
167127 </ template >
168- < script type =" text/markdown " > ${ x } </ script >
128+ ${ this . #renderMarkdown ( x ) }
169129 </ zero-md > ` ) }
170130 </ pf-tooltip >
171131 ${ isBoolean ? html `
@@ -186,6 +146,12 @@ export class PftElementKnobs<T extends HTMLElement> extends LitElement {
186146 ` ;
187147 }
188148
149+ #renderMarkdown( md ?: string ) {
150+ return ! md ? '' : html `
151+ < script type ="text/markdown "> ${ md } </ script >
152+ ` ;
153+ }
154+
189155 #renderContent( slots : Slot [ ] , info : ContentKnobInfo < T > ) {
190156 // todo : change listener is inflexible
191157 return html `
@@ -199,19 +165,34 @@ export class PftElementKnobs<T extends HTMLElement> extends LitElement {
199165 < zero-md > < script type ="text/markdown "> ${ x . description ?? '' } </ script > </ zero-md >
200166 </ dd > ` ) }
201167 </ dl >
202- < pft-html-editor id ="${ info . knobId } "
203- @input ="${ this . #onKnobChangedContent} "
204- .value ="${ info . element . innerHTML } "> </ pft-html-editor >
168+ < pf-code-block >
169+ < pft-html-editor id ="${ info . knobId } "
170+ @input ="${ this . #onKnobChangedContent} "
171+ .value ="${ dedent ( info . element . innerHTML ) } "> </ pft-html-editor >
172+ </ pf-code-block >
205173 ` ;
206174 }
207175
208176 #renderKnobs( ) {
209177 const decl = this . #elementDecl;
210178 const { element, tag, manifest } = this ;
211179 if ( element && decl && tag && manifest ) {
212- const { attributes, slots } = decl ;
180+ const {
181+ summary,
182+ description,
183+ attributes,
184+ members,
185+ slots,
186+ } = decl ;
187+
188+ const properties = members ?. filter ( isAttributelessProperty ) ?? [ ] ;
189+
213190 return html `
214- < form @submit ="${ ( e : Event ) => e . preventDefault ( ) } ">
191+ < hr >
192+ < form id ="knobs " @submit ="${ ( e : Event ) => e . preventDefault ( ) } ">
193+ < h2 > < code > <${ tag } ></ code > </ h2 >
194+ < zero-md > ${ this . #renderMarkdown( summary ) } </ zero-md >
195+ < zero-md > ${ this . #renderMarkdown( description ) } </ zero-md >
215196 ${ ! attributes ? '' : html `
216197 < section id ="attributes "
217198 @change ="${ this . #onKnobChangeAttribute} "
0 commit comments