diff --git a/src/dom/node-parser.ts b/src/dom/node-parser.ts index adf4256..f00c02b 100644 --- a/src/dom/node-parser.ts +++ b/src/dom/node-parser.ts @@ -20,21 +20,32 @@ const parseNodeTree = (node: Node, parent: ElementContainer, root: ElementContai if (isTextNode(childNode) && childNode.data.trim().length > 0) { parent.textNodes.push(new TextContainer(childNode, parent.styles)); } else if (isElementNode(childNode)) { - const container = createContainer(childNode); - if (container.styles.isVisible()) { - if (createsRealStackingContext(childNode, container, root)) { - container.flags |= FLAGS.CREATES_REAL_STACKING_CONTEXT; - } else if (createsStackingContext(container.styles)) { - container.flags |= FLAGS.CREATES_STACKING_CONTEXT; - } + if (isSlotElement(childNode) && childNode.assignedNodes) { + childNode.assignedNodes().forEach((childNode) => parseNodeTree(childNode, parent, root)); + } else { + const container = createContainer(childNode); + if (container.styles.isVisible()) { + 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) { - container.flags |= FLAGS.IS_LIST_OWNER; - } + if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) { + container.flags |= FLAGS.IS_LIST_OWNER; + } - parent.elements.push(container); - if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) { - parseNodeTree(childNode, container, root); + parent.elements.push(container); + childNode.slot; + 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 isTextareaElement = (node: Element): node is HTMLTextAreaElement => node.tagName === 'TEXTAREA'; export const isSelectElement = (node: Element): node is HTMLSelectElement => node.tagName === 'SELECT'; +export const isSlotElement = (node: Element): node is HTMLSlotElement => node.tagName === 'SLOT'; diff --git a/tests/reftests/webcomponents/autonomous-custom-element.js b/tests/reftests/webcomponents/autonomous-custom-element.js new file mode 100644 index 0000000..659cb56 --- /dev/null +++ b/tests/reftests/webcomponents/autonomous-custom-element.js @@ -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); diff --git a/tests/reftests/webcomponents/slot-element.js b/tests/reftests/webcomponents/slot-element.js new file mode 100644 index 0000000..53595ba --- /dev/null +++ b/tests/reftests/webcomponents/slot-element.js @@ -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}".`); + }); + } + } +); diff --git a/tests/reftests/webcomponents/webcomponents.html b/tests/reftests/webcomponents/webcomponents.html new file mode 100644 index 0000000..cfa59f1 --- /dev/null +++ b/tests/reftests/webcomponents/webcomponents.html @@ -0,0 +1,53 @@ + + +
+A common, sweet, crunchy fruit, usually green or yellow in color.
+A fairly common, sweet, usually green fruit, usually softer than Apples.
+A long, curved, yellow fruit, with a fairly gentle flavor.
+Orange in color, usually sweet but can be sharp, often contains pips.
+An orange fruit with big stone in the middle, and sweet, juicy flesh.
+A red fruit with yellow seeds on the outside; has a sweet flavor and a pretty shape.
+They are berries and they are blue; sweet in flavor, small in size, round.
+