Skip to content

Commit c90d56d

Browse files
committed
Add <wco-element-page>
1 parent cd8ee71 commit c90d56d

File tree

4 files changed

+146
-103
lines changed

4 files changed

+146
-103
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
* @license
3+
* Copyright 2022 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import {html, css, LitElement} from 'lit';
8+
import {customElement, property} from 'lit/decorators.js';
9+
10+
import type {Package, Reference} from 'custom-elements-manifest/schema.js';
11+
import {
12+
getModule,
13+
parseReferenceString,
14+
resolveReference,
15+
normalizeModulePath,
16+
} from '@webcomponents/custom-elements-manifest-tools';
17+
18+
import './wco-top-bar.js';
19+
20+
export interface ElementData {
21+
packageName: string;
22+
elementName: string;
23+
declarationReference: string;
24+
customElementExport: string;
25+
manifest: Package;
26+
}
27+
28+
@customElement('wco-element-page')
29+
export class WCOElementPage extends LitElement {
30+
static styles = css`
31+
:host {
32+
display: flex;
33+
flex-direction: column;
34+
}
35+
36+
.full-screen-error {
37+
display: flex;
38+
flex: 1;
39+
align-items: center;
40+
justify-items: center;
41+
}
42+
`;
43+
44+
@property()
45+
elementData?: ElementData;
46+
47+
render() {
48+
if (this.elementData === undefined) {
49+
return html`
50+
<wco-top-bar></wco-top-bar>
51+
<div class="full-screen-error">No element to display</div>
52+
`;
53+
}
54+
const {
55+
packageName,
56+
elementName,
57+
declarationReference,
58+
customElementExport,
59+
manifest,
60+
} = this.elementData;
61+
const ceExportRef = parseReferenceString(customElementExport);
62+
const declarationRef = parseReferenceString(declarationReference);
63+
const module =
64+
declarationRef.module === undefined
65+
? undefined
66+
: getModule(manifest, declarationRef.module);
67+
const declaration =
68+
module === undefined
69+
? undefined
70+
: resolveReference(manifest, module, declarationRef, packageName, '');
71+
72+
if (declaration === undefined || declaration.kind !== 'class') {
73+
return html`
74+
<wco-top-bar></wco-top-bar>
75+
<div class="full-screen-error">Could not find element declaration</div>
76+
`;
77+
}
78+
79+
const fields = declaration.members?.filter((m) => m.kind === 'field');
80+
const methods = declaration.members?.filter((m) => m.kind === 'method');
81+
82+
return html`
83+
<wco-top-bar></wco-top-bar>
84+
<h1>${packageName}/${elementName}</h1>
85+
<h3>${declaration.summary}</h3>
86+
87+
<p>${declaration.description}</p>
88+
89+
<h2>Usage</h2>
90+
<pre><code>
91+
import '${getElementImportSpecifier(packageName, ceExportRef)}';
92+
</code></pre>
93+
94+
<h2>Fields</h2>
95+
<ul>
96+
${fields?.map((f) => html`<li>${f.name}: ${f.description}</li>`)}
97+
</ul>
98+
99+
<h2>Methods</h2>
100+
<ul>
101+
${methods?.map((m) => html`<li>${m.name}: ${m.description}</li>`)}
102+
</ul>
103+
`;
104+
}
105+
}
106+
107+
declare global {
108+
interface HTMLElementTagNameMap {
109+
'wco-element-page': WCOElementPage;
110+
}
111+
}
112+
113+
const getElementImportSpecifier = (
114+
packageName: string,
115+
ceExportRef: Reference
116+
) =>
117+
ceExportRef.module === undefined
118+
? packageName
119+
: `${packageName}/${normalizeModulePath(ceExportRef.module)}`;

packages/site-client/src/entrypoints/element.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
import '../components/wco-top-bar.js';
7+
import '../components/wco-element-page.js';

packages/site-server/src/catalog/routes/element/element-route.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
* Copyright 2022 Google LLC
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6+
7+
// This must be imported before lit
8+
import {render} from '@lit-labs/ssr/lib/render-with-global-dom-shim.js';
9+
610
import {DefaultContext, DefaultState, ParameterizedContext} from 'koa';
11+
import {html} from 'lit';
712
import {Readable} from 'stream';
813
import {gql} from '@apollo/client/core/index.js';
914
import Router from '@koa/router';
10-
import {render} from '@lit-labs/ssr/lib/render-with-global-dom-shim.js';
1115

16+
import '@webcomponents/internal-site-client/lib/entrypoints/element.js';
1217
import {renderPage} from '../../../templates/base.js';
1318
import {client} from '../../graphql.js';
14-
import {renderElement} from './element-template.js';
1519

1620
export const handleElementRoute = async (
1721
context: ParameterizedContext<
@@ -78,22 +82,26 @@ export const handleElementRoute = async (
7882
throw new Error('Internal error');
7983
}
8084

81-
context.body = Readable.from(renderPage({
82-
title: `${packageName}/${elementName}`,
83-
scripts: [
84-
'/js/hydrate.js',
85-
'/js/element.js'
86-
],
87-
content: render(
88-
renderElement({
89-
packageName: packageName,
90-
elementName: elementName,
91-
declarationReference: customElement.declaration,
92-
customElementExport: customElement.export,
93-
manifest: customElementsManifest,
94-
})
95-
),
96-
}));
85+
const elementData = {
86+
packageName: packageName,
87+
elementName: elementName,
88+
declarationReference: customElement.declaration,
89+
customElementExport: customElement.customElementExport,
90+
manifest: customElementsManifest,
91+
};
92+
9793
context.type = 'html';
9894
context.status = 200;
95+
context.body = Readable.from(
96+
renderPage({
97+
title: `${packageName}/${elementName}`,
98+
scripts: ['/js/hydrate.js', '/js/element.js'],
99+
// TODO (justinfagnani): If we want to hydrate, we need to serialize the
100+
// initial data and embed in the response
101+
content: render(
102+
html`<wco-element-page .elementData=${elementData}></wco-element-page>`,
103+
{deferHydration: true}
104+
),
105+
})
106+
);
99107
};

packages/site-server/src/catalog/routes/element/element-template.ts

Lines changed: 0 additions & 84 deletions
This file was deleted.

0 commit comments

Comments
 (0)