Skip to content

Commit

Permalink
feat: terse Fragment syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
dbushong committed Dec 22, 2019
1 parent 625615d commit 659f4e0
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 1 deletion.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ class SomeComponent extends Component {
module.exports = SomeComponent;
```

You can create a Fragment tersely by passing only one argument: an
array of other nodes or strings:

```js
const frag = h([
h('div', 'one'),
h('div', 'two'),
'three'
]);

// is equivalent to:

const { Fragment } = require('preact');
const frag = h(Fragment, [
h('div', 'one'),
h('div', 'two'),
'three'
]);

## Optional Tag Helpers

At the cost of a modestly larger import and slight function call overhead,
Expand Down
10 changes: 9 additions & 1 deletion lib/phy.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,19 @@ function isAttributes(obj) {
// possible arg combos (eliding createElement) (kids* = 0-or-more-kids):
/**
* @param {typeof preact.createElement} createElement
* @param {string | ComponentType} selector
* @param {string | ComponentType | (string | ComponentType)[]} selector
* @param {Readonly<Record<string, any>>} [attrs]
* @param {ComponentChildren[]} kids
* @return {preact.VNode}
*/
function h(createElement, selector, attrs, ...kids) {
if (Array.isArray(selector)) {
if (attrs != null || kids.length > 0) {
throw new Error('Fragment mode does not accept attrs or kids');
}
return h(createElement, preact.Fragment, undefined, selector);
}

if (attrs) {
if (!isAttributes(attrs)) {
kids.unshift(/** @type {ComponentChildren} */ (attrs));
Expand Down
1 change: 1 addition & 0 deletions lib/typedefs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import p from 'preact';

declare function isPreactNode(obj: object): boolean;

declare function phy(fragments: (string | ComponentType)[]): VNode;
declare function phy(
selectorOrComp: string | ComponentType,
...kids: ComponentChildren[]
Expand Down
16 changes: 16 additions & 0 deletions test/phy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ const tests = [
h('litter-box', {}, [h(Fragment, {}, ['kitten', h('toy', 'mouse')])]),
'<litter-box>kitten<toy>mouse</toy></litter-box>',
],
[
'Fragment terse usage',
h(['kitten', h('toy', 'mouse')]),
'kitten<toy>mouse</toy>',
],
];

describe('phy', () => {
Expand All @@ -102,6 +107,17 @@ describe('phy', () => {
assert.equal(test[2], render(test[1]));
});
});

it('throws on surplus fragment args', () => {
assert.include(
'Fragment mode',
assert.throws(() => h(['a', 'b'], { some: 'attr' })).message
);
assert.include(
'Fragment mode',
assert.throws(() => h(['a', 'b'], undefined, 'kid')).message
);
});
});

describe('isVNode', () => {
Expand Down

0 comments on commit 659f4e0

Please sign in to comment.