feat: support for custom and slot elements (#2581)

This commit is contained in:
Niklas von Hertzen 2021-07-14 17:59:08 +08:00 committed by GitHub
parent eeb5a3ea1d
commit acb4cd24b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 174 additions and 13 deletions

View File

@ -20,21 +20,32 @@ const parseNodeTree = (node: Node, parent: ElementContainer, root: ElementContai
if (isTextNode(childNode) && childNode.data.trim().length > 0) { if (isTextNode(childNode) && childNode.data.trim().length > 0) {
parent.textNodes.push(new TextContainer(childNode, parent.styles)); parent.textNodes.push(new TextContainer(childNode, parent.styles));
} else if (isElementNode(childNode)) { } else if (isElementNode(childNode)) {
const container = createContainer(childNode); if (isSlotElement(childNode) && childNode.assignedNodes) {
if (container.styles.isVisible()) { childNode.assignedNodes().forEach((childNode) => parseNodeTree(childNode, parent, root));
if (createsRealStackingContext(childNode, container, root)) { } else {
container.flags |= FLAGS.CREATES_REAL_STACKING_CONTEXT; const container = createContainer(childNode);
} else if (createsStackingContext(container.styles)) { if (container.styles.isVisible()) {
container.flags |= FLAGS.CREATES_STACKING_CONTEXT; if (createsRealStackingContext(childNode, container, root)) {
} container.flags |= FLAGS.CREATES_REAL_STACKING_CONTEXT;
} else if (createsStackingContext(container.styles)) {
container.flags |= FLAGS.CREATES_STACKING_CONTEXT;
}
if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) { if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) {
container.flags |= FLAGS.IS_LIST_OWNER; container.flags |= FLAGS.IS_LIST_OWNER;
} }
parent.elements.push(container); parent.elements.push(container);
if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) { childNode.slot;
parseNodeTree(childNode, container, root); if (childNode.shadowRoot) {
parseNodeTree(childNode.shadowRoot, container, root);
} else if (
!isTextareaElement(childNode) &&
!isSVGElement(childNode) &&
!isSelectElement(childNode)
) {
parseNodeTree(childNode, container, root);
}
} }
} }
} }
@ -118,3 +129,4 @@ export const isStyleElement = (node: Element): node is HTMLStyleElement => node.
export const isScriptElement = (node: Element): node is HTMLScriptElement => node.tagName === 'SCRIPT'; export const isScriptElement = (node: Element): node is HTMLScriptElement => node.tagName === 'SCRIPT';
export const isTextareaElement = (node: Element): node is HTMLTextAreaElement => node.tagName === 'TEXTAREA'; export const isTextareaElement = (node: Element): node is HTMLTextAreaElement => node.tagName === 'TEXTAREA';
export const isSelectElement = (node: Element): node is HTMLSelectElement => node.tagName === 'SELECT'; export const isSelectElement = (node: Element): node is HTMLSelectElement => node.tagName === 'SELECT';
export const isSlotElement = (node: Element): node is HTMLSlotElement => node.tagName === 'SLOT';

View File

@ -0,0 +1,45 @@
class AutonomousCustomElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const wrapper = document.createElement('span');
wrapper.setAttribute('class', 'wrapper');
const info = document.createElement('span');
info.setAttribute('class', 'info');
info.textContent = this.getAttribute('text');
const img = document.createElement('img');
img.src = this.getAttribute('img');
// Create some CSS to apply to the shadow dom
const style = document.createElement('style');
style.textContent = `
.wrapper {
position: relative;
}
.info {
font-size: 0.8rem;
width: 200px;
display: inline-block;
border: 1px solid black;
padding: 10px;
background: white;
border-radius: 10px;
}
img {
width: 100px;
}
`;
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.appendChild(img);
wrapper.appendChild(info);
}
}
customElements.define('autonomous-custom-element', AutonomousCustomElement);

View File

@ -0,0 +1,51 @@
customElements.define('summary-display',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('summary-display-template');
const templateContent = template.content;
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(templateContent.cloneNode(true));
const items = Array.from(this.querySelectorAll('li'));
const descriptions = Array.from(this.querySelectorAll('p'));
items.forEach(item => {
handleClick(item);
});
descriptions.forEach(description => {
updateDisplay(description, items[1]);
});
function handleClick(item) {
item.addEventListener('click', function() {
items.forEach(item => {
item.style.backgroundColor = 'white';
});
descriptions.forEach(description => {
updateDisplay(description, item);
});
});
}
function updateDisplay(description, item) {
description.removeAttribute('slot');
if(description.getAttribute('data-name') === item.textContent) {
description.setAttribute('slot', 'choice');
item.style.backgroundColor = '#bad0e4';
}
}
const slots = this.shadowRoot.querySelectorAll('slot');
slots[1].addEventListener('slotchange', function(e) {
const nodes = slots[1].assignedNodes();
console.log(`Element in Slot "${slots[1].name}" changed to "${nodes[0].outerHTML}".`);
});
}
}
);

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<title>Web components tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../../test.js"></script>
<style>
</style>
</head>
<body>
<div>
<h1>Autonomous custom element</h1>
<autonomous-custom-element img="../../assets/image.jpg" text="This is text"></autonomous-custom-element>
<h1>Slot element</h1>
<summary-display>
<ul slot="master-list">
<li>Apples</li>
<li>Pears</li>
<li>Bananas</li>
<li>Oranges</li>
<li>Peaches</li>
<li>Strawberries</li>
<li>Blueberries</li>
</ul>
<p data-name="Apples">A common, sweet, crunchy fruit, usually green or yellow in color.</p>
<p data-name="Pears">A fairly common, sweet, usually green fruit, usually softer than Apples.</p>
<p data-name="Bananas">A long, curved, yellow fruit, with a fairly gentle flavor.</p>
<p data-name="Oranges">Orange in color, usually sweet but can be sharp, often contains pips.</p>
<p data-name="Peaches">An orange fruit with big stone in the middle, and sweet, juicy flesh.</p>
<p data-name="Strawberries">A red fruit with yellow seeds on the outside; has a sweet flavor and a pretty shape.</p>
<p data-name="Blueberries">They are berries and they are blue; sweet in flavor, small in size, round.</p>
</summary-display>
<template id="summary-display-template">
<article>
<div>
<slot name="master-list"></slot>
</div>
<div>
<slot name="choice"></slot>
</div>
</article>
</template>
<script src="autonomous-custom-element.js"></script>
<script src="slot-element.js"></script>
</div>
</body>
</html>