Skip to content

Commit 02f98c5

Browse files
authored
Merge branch 'master' into h-component-test
2 parents e53e306 + 5d6a2c4 commit 02f98c5

File tree

8 files changed

+91
-29
lines changed

8 files changed

+91
-29
lines changed

README.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
[![OpenCollective Sponsors](https://opencollective.com/preact/sponsors/badge.svg)](#sponsors)
4848
[![travis](https://travis-ci.org/developit/preact.svg?branch=master)](https://travis-ci.org/developit/preact)
4949
[![coveralls](https://img.shields.io/coveralls/developit/preact/master.svg)](https://coveralls.io/github/developit/preact)
50+
[![gzip size](http://img.badgesize.io/https://unpkg.com/preact/dist/preact.min.js?compression=gzip)](https://unpkg.com/preact/dist/preact.min.js)
5051

5152
Preact supports modern browsers and IE9+:
5253

@@ -82,6 +83,7 @@ Preact supports modern browsers and IE9+:
8283
- [**Color Picker**](https://colors.now.sh) _([Github Project](https://github.com/lukeed/colors-app))_ :art:
8384
- [**Rainbow Explorer**](https://use-the-platform.com/rainbow-explorer/) _([Github Project](https://github.com/vaneenige/rainbow-explorer/))_ :rainbow:
8485
- [**Offline Gallery**](https://use-the-platform.com/offline-gallery/) _([Github Project](https://github.com/vaneenige/offline-gallery/))_ :balloon:
86+
- [**Periodic Weather**](https://use-the-platform.com/periodic-weather/) _([Github Project](https://github.com/vaneenige/periodic-weather/))_ :sunny:
8587

8688
## Libraries & Add-ons
8789

@@ -98,9 +100,6 @@ Preact supports modern browsers and IE9+:
98100
- :thought_balloon: [**preact-socrates**](https://github.com/matthewmueller/preact-socrates): Preact plugin for [Socrates](http://github.com/matthewmueller/socrates)
99101
- :rowboat: [**preact-flyd**](https://github.com/xialvjun/preact-flyd): Use [flyd](https://github.com/paldepind/flyd) FRP streams in Preact + JSX
100102
- :speech_balloon: [**preact-i18nline**](https://github.com/download/preact-i18nline): Integrates the ecosystem around [i18n-js](https://github.com/everydayhero/i18n-js) with Preact via [i18nline](https://github.com/download/i18nline).
101-
- :metal: [**preact-mui**](https://git.io/v1aVO): The MUI CSS Preact library.
102-
- :white_square_button: [**preact-mdl**](https://git.io/preact-mdl): Use [MDL](https://getmdl.io) as Preact components
103-
- :rocket: [**preact-photon**](https://git.io/preact-photon): build beautiful desktop UI with [photon](http://photonkit.com)
104103
- :microscope: [**preact-jsx-chai**](https://git.io/preact-jsx-chai): JSX assertion testing _(no DOM, right in Node)_
105104
- :tophat: [**preact-classless-component**](https://github.com/ld0rman/preact-classless-component): create preact components without the class keyword
106105
- :hammer: [**preact-hyperscript**](https://github.com/queckezz/preact-hyperscript): Hyperscript-like syntax for creating elements
@@ -109,6 +108,17 @@ Preact supports modern browsers and IE9+:
109108
- :construction_worker: [**preact-helmet**](https://github.com/download/preact-helmet): A document head manager for Preact
110109
- :necktie: [**preact-delegate**](https://github.com/NekR/preact-delegate): Delegate DOM events
111110

111+
#### UI Component Libraries
112+
113+
> Want to prototype something or speed up your development? Try one of these toolkits:
114+
115+
- [**preact-material-components**](https://github.com/prateekbh/preact-material-components): Material Design Components for Preact ([website](https://prateekbh.github.io/preact-material-components/))
116+
- [**preact-mdc**](https://github.com/BerndWessels/preact-mdc): Material Design Components for Preact ([demo](https://github.com/BerndWessels/preact-mdc-demo))
117+
- [**preact-mui**](https://git.io/v1aVO): The MUI CSS Preact library.
118+
- [**preact-photon**](https://git.io/preact-photon): build beautiful desktop UI with [photon](http://photonkit.com)
119+
- [**preact-mdl**](https://git.io/preact-mdl): [Material Design Lite](https://getmdl.io) for Preact
120+
121+
112122
---
113123

114124
## Getting Started
@@ -294,18 +304,23 @@ class Foo extends Component {
294304

295305
While this achieves much better runtime performance, it's still a lot of unnecessary code to wire up state to UI.
296306

297-
Fortunately there is a solution, in the form of `linkState()`. Calling `component.linkState('text')` returns a function that accepts an Event and uses it's associated value to update the given property in your component's state. Calls to linkState() with the same state property are cached, so there is no performance penalty. Here is the previous example rewritten using _Linked State_:
307+
Fortunately there is a solution, in the form of a module called [linkstate](https://github.com/developit/linkstate). Calling `linkState(component, 'text')` returns a function that accepts an Event and uses it's associated value to update the given property in your component's state. Calls to `linkState()` with the same arguments are cached, so there is no performance penalty. Here is the previous example rewritten using _Linked State_:
298308

299309
```js
310+
import linkState from 'linkstate';
311+
300312
class Foo extends Component {
301313
render({ }, { text }) {
302-
return <input value={text} onInput={this.linkState('text')} />;
314+
return <input value={text} onInput={linkState(this, 'text')} />;
303315
}
304316
}
305317
```
306318

307319
Simple and effective. It handles linking state from any input type, or an optional second parameter can be used to explicitly provide a keypath to the new state value.
308320

321+
> **Note:** In Preact 7 and prior, `linkState()` was built right into Component. In 8.0, it was moved to a separate module. You can restore the 7.x behavior by using linkstate as a polyfill - see [the linkstate docs](https://github.com/developit/linkstate#usage).
322+
323+
309324

310325
## Examples
311326

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"lint": "eslint devtools src test",
2828
"prepublish": "npm run build",
2929
"smart-release": "npm run build && npm test && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish",
30-
"release": "cross-env npm run smart-release"
30+
"release": "cross-env npm run smart-release",
31+
"postinstall": "npm run -s donate",
32+
"donate": "echo \"\n *** Thanks for downloading Preact! ***\nPlease consider donating to our open collective\n\n => https://opencollective.com/preact/donate\n\""
3133
},
3234
"eslintConfig": {
3335
"extends": "./config/eslint-config.js"
@@ -102,7 +104,7 @@
102104
"sinon-chai": "^2.8.0",
103105
"typescript": "^2.2.2",
104106
"uglify-js": "^2.7.5",
105-
"webpack": "^1.13.1"
107+
"webpack": "^2.4.1"
106108
},
107109
"greenkeeper": {
108110
"ignore": [

src/dom/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export function createNode(nodeName, isSvg) {
1818
* @param {Element} node The node to remove
1919
*/
2020
export function removeNode(node) {
21-
if (node.parentNode) node.parentNode.removeChild(node);
21+
let parentNode = node.parentNode;
22+
if (parentNode) parentNode.removeChild(node);
2223
}
2324

2425

src/h.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function h(nodeName, attributes) {
2525
for (i=child.length; i--; ) stack.push(child[i]);
2626
}
2727
else {
28-
if (child===true || child===false) child = null;
28+
if (typeof child==='boolean') child = null;
2929

3030
if ((simple = typeof nodeName!=='function')) {
3131
if (child==null) child = '';

src/preact.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ declare namespace JSX {
384384
// Form Events
385385
onChange?:GenericEventHandler;
386386
onInput?:GenericEventHandler;
387+
onSearch?:GenericEventHandler;
387388
onSubmit?:GenericEventHandler;
388389

389390
// Keyboard Events

src/vdom/diff.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ function idiff(dom, vnode, context, mountAll, componentRoot) {
6565
let out = dom,
6666
prevSvgMode = isSvgMode;
6767

68-
// empty values (null & undefined) render as empty Text nodes
69-
if (vnode==null) vnode = '';
68+
// empty values (null, undefined, booleans) render as empty Text nodes
69+
if (vnode==null || typeof vnode==='boolean') vnode = '';
7070

7171

72-
// Fast case: Strings create/update Text nodes.
73-
if (typeof vnode==='string') {
72+
// Fast case: Strings & Numbers create/update Text nodes.
73+
if (typeof vnode==='string' || typeof vnode==='number') {
7474

7575
// update if it's already a Text node:
7676
if (dom && dom.splitText!==undefined && dom.parentNode && (!dom._component || componentRoot)) {
@@ -94,18 +94,20 @@ function idiff(dom, vnode, context, mountAll, componentRoot) {
9494

9595

9696
// If the VNode represents a Component, perform a component diff:
97-
if (typeof vnode.nodeName==='function') {
97+
let vnodeName = vnode.nodeName;
98+
if (typeof vnodeName==='function') {
9899
return buildComponentFromVNode(dom, vnode, context, mountAll);
99100
}
100101

101102

102103
// Tracks entering and exiting SVG namespace when descending through the tree.
103-
isSvgMode = vnode.nodeName==='svg' ? true : vnode.nodeName==='foreignObject' ? false : isSvgMode;
104+
isSvgMode = vnodeName==='svg' ? true : vnodeName==='foreignObject' ? false : isSvgMode;
104105

105106

106107
// If there's no existing element or it's the wrong type, create a new one:
107-
if (!dom || !isNamedNode(dom, String(vnode.nodeName))) {
108-
out = createNode(String(vnode.nodeName), isSvgMode);
108+
vnodeName = String(vnodeName);
109+
if (!dom || !isNamedNode(dom, vnodeName)) {
110+
out = createNode(vnodeName, isSvgMode);
109111

110112
if (dom) {
111113
// move children into the replacement node

test/browser/render.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,46 @@ describe('render()', () => {
8989
expect(scratch.firstChild).to.have.property('innerHTML', ',,,0,NaN');
9090
});
9191

92+
it('should not render null', () => {
93+
render(null, scratch);
94+
expect(scratch.innerHTML).to.equal('');
95+
});
96+
97+
it('should not render undefined', () => {
98+
render(undefined, scratch);
99+
expect(scratch.innerHTML).to.equal('');
100+
});
101+
102+
it('should not render boolean true', () => {
103+
render(true, scratch);
104+
expect(scratch.innerHTML).to.equal('');
105+
});
106+
107+
it('should not render boolean false', () => {
108+
render(false, scratch);
109+
expect(scratch.innerHTML).to.equal('');
110+
});
111+
112+
it('should render NaN as text content', () => {
113+
render(NaN, scratch);
114+
expect(scratch.innerHTML).to.equal('NaN');
115+
});
116+
117+
it('should render numbers (0) as text content', () => {
118+
render(0, scratch);
119+
expect(scratch.innerHTML).to.equal('0');
120+
});
121+
122+
it('should render numbers (42) as text content', () => {
123+
render(42, scratch);
124+
expect(scratch.innerHTML).to.equal('42');
125+
});
126+
127+
it('should render strings as text content', () => {
128+
render('Testing, huh! How is it going?', scratch);
129+
expect(scratch.innerHTML).to.equal('Testing, huh! How is it going?');
130+
});
131+
92132
it('should clear falsey attributes', () => {
93133
let root = render((
94134
<div anull="anull" aundefined="aundefined" afalse="afalse" anan="aNaN" a0="a0" />

test/karma.conf.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,32 +111,33 @@ module.exports = function(config) {
111111
devtool: 'inline-source-map',
112112
module: {
113113
/* Transpile source and test files */
114-
preLoaders: [
114+
rules: [
115115
{
116+
enforce: 'pre',
116117
test: /\.jsx?$/,
117118
exclude: /node_modules/,
118-
loader: 'babel',
119-
query: {
119+
loader: 'babel-loader',
120+
options: {
120121
loose: 'all',
121122
blacklist: ['es6.tailCall'],
122123
comments: false,
123124
compact: true
124125
}
125-
}
126-
],
127-
/* Only Instrument our source files for coverage */
128-
loaders: [].concat( coverage ? {
129-
test: /\.jsx?$/,
130-
loader: 'isparta',
131-
include: /src/
132-
} : [])
126+
},
127+
/* Only Instrument our source files for coverage */
128+
coverage ? {
129+
test: /\.jsx?$/,
130+
loader: 'isparta-loader',
131+
include: /src/
132+
} : {}
133+
]
133134
},
134135
resolve: {
135136
// The React DevTools integration requires preact as a module
136137
// rather than referencing source files inside the module
137138
// directly
138139
alias: { preact: '../src/preact' },
139-
modulesDirectories: [__dirname, 'node_modules']
140+
modules: [__dirname, 'node_modules']
140141
},
141142
plugins: [
142143
new webpack.DefinePlugin({

0 commit comments

Comments
 (0)