Skip to content

Commit e277fd0

Browse files
paull39rschristian
andauthored
Provide light dom props children (#79)
* Add tests * Pass shadow option to the toVdom Method and process light dom props.children correct * Topmost node could also be a non element node * chore: Remove all the superfluous comments * test: Rewrite tests & check implict shadow behavior * fix: Ensure implicit shadow behavior matches explicit * refactor: Simplify pseudo slot impl --------- Co-authored-by: Ryan Christian <[email protected]>
1 parent 390021e commit e277fd0

File tree

2 files changed

+82
-9
lines changed

2 files changed

+82
-9
lines changed

src/index.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, cloneElement, render, hydrate } from 'preact';
1+
import { h, cloneElement, render, hydrate, Fragment } from 'preact';
22

33
/**
44
* @typedef {import('./index.d.ts').PreactCustomElement} PreactCustomElement
@@ -26,7 +26,9 @@ export default function register(Component, tagName, propNames, options) {
2626
}
2727
PreactElement.prototype = Object.create(HTMLElement.prototype);
2828
PreactElement.prototype.constructor = PreactElement;
29-
PreactElement.prototype.connectedCallback = connectedCallback;
29+
PreactElement.prototype.connectedCallback = function () {
30+
connectedCallback.call(this, options);
31+
};
3032
PreactElement.prototype.attributeChangedCallback = attributeChangedCallback;
3133
PreactElement.prototype.disconnectedCallback = disconnectedCallback;
3234

@@ -89,7 +91,7 @@ function ContextProvider(props) {
8991
/**
9092
* @this {PreactCustomElement}
9193
*/
92-
function connectedCallback() {
94+
function connectedCallback(options) {
9395
// Obtain a reference to the previous context by pinging the nearest
9496
// higher up node that was rendered with Preact. If one Preact component
9597
// higher up receives our ping, it will set the `detail` property of
@@ -106,7 +108,7 @@ function connectedCallback() {
106108
this._vdom = h(
107109
ContextProvider,
108110
{ ...this._props, context },
109-
toVdom(this, this._vdomComponent)
111+
toVdom(this, this._vdomComponent, options)
110112
);
111113
(this.hasAttribute('hydrate') ? hydrate : render)(this._vdom, this._root);
112114
}
@@ -170,10 +172,11 @@ function Slot(props, context) {
170172
}
171173
}
172174
};
173-
return h('slot', { ...props, ref });
175+
const { useFragment, ...rest } = props;
176+
return h(useFragment ? Fragment : 'slot', { ...rest, ref });
174177
}
175178

176-
function toVdom(element, nodeName) {
179+
function toVdom(element, nodeName, options) {
177180
if (element.nodeType === 3) return element.data;
178181
if (element.nodeType !== 1) return null;
179182
let children = [],
@@ -189,7 +192,7 @@ function toVdom(element, nodeName) {
189192
}
190193

191194
for (i = cn.length; i--; ) {
192-
const vnode = toVdom(cn[i], null);
195+
const vnode = toVdom(cn[i], null, options);
193196
// Move slots correctly
194197
const name = cn[i].slot;
195198
if (name) {
@@ -199,7 +202,15 @@ function toVdom(element, nodeName) {
199202
}
200203
}
201204

205+
const shadow = !!(options && options.shadow);
206+
202207
// Only wrap the topmost node with a slot
203-
const wrappedChildren = nodeName ? h(Slot, null, children) : children;
208+
const wrappedChildren = nodeName
209+
? h(Slot, { useFragment: !shadow }, children)
210+
: children;
211+
212+
if (!shadow && nodeName) {
213+
element.innerHTML = '';
214+
}
204215
return h(nodeName || element.nodeName.toLowerCase(), props, wrappedChildren);
205216
}

src/index.test.jsx

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
import { assert } from '@open-wc/testing';
2-
import { h, createContext, Component } from 'preact';
2+
import { h, createContext, Component, Fragment } from 'preact';
33
import { useContext } from 'preact/hooks';
44
import { act } from 'preact/test-utils';
55
import registerElement from './index';
66

7+
/** @param {string} name */
8+
function createTestElement(name) {
9+
const el = document.createElement(name);
10+
const child1 = document.createElement('p');
11+
child1.textContent = 'Child 1';
12+
const child2 = document.createElement('p');
13+
child2.textContent = 'Child 2';
14+
el.appendChild(child1);
15+
el.appendChild(child2);
16+
return el;
17+
}
18+
719
describe('web components', () => {
820
/** @type {HTMLDivElement} */
921
let root;
@@ -359,4 +371,54 @@ describe('web components', () => {
359371
const style = getComputedStyle(child);
360372
assert.equal(style.color, 'rgb(255, 0, 0)');
361373
});
374+
375+
it('supports controlling light DOM children', async () => {
376+
function LightDomChildren({ children }) {
377+
return (
378+
<Fragment>
379+
<h1>Light DOM Children</h1>
380+
<div>{children}</div>
381+
</Fragment>
382+
);
383+
}
384+
385+
registerElement(LightDomChildren, 'light-dom-children', []);
386+
registerElement(LightDomChildren, 'light-dom-children-shadow-false', [], {
387+
shadow: false,
388+
});
389+
390+
root.appendChild(createTestElement('light-dom-children'));
391+
root.appendChild(createTestElement('light-dom-children-shadow-false'));
392+
393+
assert.equal(
394+
document.querySelector('light-dom-children').innerHTML,
395+
'<h1>Light DOM Children</h1><div><p>Child 1</p><p>Child 2</p></div>'
396+
);
397+
assert.equal(
398+
document.querySelector('light-dom-children-shadow-false').innerHTML,
399+
'<h1>Light DOM Children</h1><div><p>Child 1</p><p>Child 2</p></div>'
400+
);
401+
});
402+
403+
it('supports controlling shadow DOM children', () => {
404+
function ShadowDomChildren({ children }) {
405+
return (
406+
<Fragment>
407+
<h1>Light DOM Children</h1>
408+
<div>{children}</div>
409+
</Fragment>
410+
);
411+
}
412+
413+
registerElement(ShadowDomChildren, 'shadow-dom-children', [], {
414+
shadow: true,
415+
});
416+
417+
root.appendChild(createTestElement('shadow-dom-children'));
418+
419+
assert.equal(
420+
document.querySelector('shadow-dom-children').shadowRoot.innerHTML,
421+
'<h1>Light DOM Children</h1><div><slot><p>Child 1</p><p>Child 2</p></slot></div>'
422+
);
423+
});
362424
});

0 commit comments

Comments
 (0)