diff --git a/docs/_utils/code-examples.js b/docs/_utils/code-examples.js
index 1e39eb12f..4efc227a8 100644
--- a/docs/_utils/code-examples.js
+++ b/docs/_utils/code-examples.js
@@ -80,9 +80,9 @@ const templates = {
}
let preview = '';
- if (attributes.viewport === undefined) {
- preview = `
${code.textContent}
`;
- }
+ // if (attributes.viewport === undefined) {
+ preview = `${code.textContent}
`;
+ // }
return `${includes}
diff --git a/src/components/code-demo/code-demo.styles.ts b/src/components/code-demo/code-demo.styles.ts
index 4992791f8..ef332dcc0 100644
--- a/src/components/code-demo/code-demo.styles.ts
+++ b/src/components/code-demo/code-demo.styles.ts
@@ -61,6 +61,10 @@ export default css`
}
}
+ wa-viewport-demo + slot[name='preview'].has-slotted {
+ display: none;
+ }
+
#source {
border-block-end: inherit;
overflow: hidden;
diff --git a/src/components/code-demo/code-demo.ts b/src/components/code-demo/code-demo.ts
index e8cef5d0a..88bca48f6 100644
--- a/src/components/code-demo/code-demo.ts
+++ b/src/components/code-demo/code-demo.ts
@@ -1,4 +1,5 @@
import '../icon/icon.js';
+import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query } from 'lit/decorators.js';
import { getInnerHTML, HasSlotController } from '../../internal/slot.js';
import { html } from 'lit';
@@ -78,11 +79,9 @@ export default class WaCodeDemo extends WebAwesomeElement {
private readonly hasSlotController = new HasSlotController(this, 'preview');
render() {
- const code = this.getDemoHTML({ type: 'preview' });
- // FIXME Ideally we don't want to render the contents of the code element anywhere if a custom preview is provided.
+ // NOTE We don't want to render the contents of the code element anywhere if a custom preview is provided.
// That way, providing a custom preview can also be used to sanitize the code.
- const customPreview = this.hasUpdated ? this.hasSlotController.test('preview') : true;
-
+ const code = this.getDemoHTML({ type: 'preview' });
let viewportHTML: string | TemplateResult = '';
if (this.viewport) {
@@ -94,11 +93,14 @@ export default class WaCodeDemo extends WebAwesomeElement {
`;
}
+ const customPreview = this.hasUpdated ? this.hasSlotController.test('preview') : true;
+
return html`
${viewportHTML}
@@ -180,7 +182,7 @@ export default class WaCodeDemo extends WebAwesomeElement {
let code;
const customPreview = this.hasUpdated ? this.hasSlotController.test('preview') : true;
if (options.type === 'preview' && customPreview && this.previewSlot) {
- code = getInnerHTML(this.previewSlot);
+ code = getHTML(this.previewSlot.assignedNodes({ flatten: true }));
} else {
code = this.querySelector?.('code')?.textContent ?? this.textContent;
}
@@ -197,10 +199,12 @@ export default class WaCodeDemo extends WebAwesomeElement {
private handleSlotChange(e: Event) {
const slot = e.target as HTMLSlotElement;
- if (slot.name === 'preview') {
+ if (slot.name === 'preview' && !this.viewport) {
const assignedNodes = slot.assignedNodes();
for (const node of assignedNodes) {
+ // Unwrap templates
+ // FIXME this will mess up the order of the nodes if there are mixed templates & regular nodes
if (node.nodeName === 'TEMPLATE') {
const content = (node as HTMLTemplateElement).content;
const clone = content.cloneNode(true);
@@ -360,3 +364,13 @@ function dedent(code: string) {
return code.replace(new RegExp(`^${minIndent}`, 'gm'), '');
}
+
+function getHTML(nodes: Iterable): string {
+ return getInnerHTML(nodes, node => {
+ if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'TEMPLATE') {
+ const template = node as HTMLTemplateElement;
+ return template.innerHTML;
+ }
+ return undefined;
+ });
+}
diff --git a/src/internal/slot.ts b/src/internal/slot.ts
index cb895b5c5..a52ce5b40 100644
--- a/src/internal/slot.ts
+++ b/src/internal/slot.ts
@@ -61,14 +61,24 @@ export class HasSlotController implements ReactiveController {
}
/**
- * Given a slot, this function iterates over all of its assigned element and text nodes and returns the concatenated
- * HTML as a string. This is useful because we can't use slot.innerHTML as an alternative.
+ * Given a list of nodes, this function iterates over all of them and returns the concatenated
+ * HTML as a string. This is useful for getting the HTML that corresponds to a slot’s assigned nodes (since we can't use slot.innerHTML as an alternative).
+ * @param nodes - The list of nodes to iterate over.
+ * @param callback - A function that can be used to customize the HTML output for specific types of nodes. If the function returns undefined, the default HTML output will be used.
*/
-export function getInnerHTML(slot: HTMLSlotElement): string {
- const nodes = slot.assignedNodes({ flatten: true });
+export function getInnerHTML(nodes: Iterable, callback?: (node: Node) => string | undefined): string {
let html = '';
- [...nodes].forEach(node => {
+ for (const node of nodes) {
+ if (callback) {
+ const customHTML = callback(node);
+
+ if (customHTML !== undefined) {
+ html += customHTML;
+ continue;
+ }
+ }
+
if (node.nodeType === Node.ELEMENT_NODE) {
html += (node as HTMLElement).outerHTML;
}
@@ -76,7 +86,7 @@ export function getInnerHTML(slot: HTMLSlotElement): string {
if (node.nodeType === Node.TEXT_NODE) {
html += node.textContent;
}
- });
+ }
return html;
}