diff --git a/.ecrc b/.ecrc
deleted file mode 100644
index 1dd9b8b..0000000
--- a/.ecrc
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "ignoreDefaults": true,
- "exclude": [
- "^coverage/",
- "^node_modules/",
- "^es/",
- "^helpers/",
- "^modules/",
- "^test/",
- "^h.d.ts",
- "^h.js",
- "^h.js.map",
- "^hooks.d.ts",
- "^hooks.js",
- "^hooks.js.map",
- "^htmldomapi.d.ts",
- "^htmldomapi.js",
- "^htmldomapi.js.map",
- "^is.d.ts",
- "^is.js",
- "^is.js.map",
- "^jsx.d.ts",
- "^jsx-global.d.ts",
- "^jsx.js",
- "^jsx.js.map",
- "^snabbdom.d.ts",
- "^snabbdom.js",
- "^snabbdom.js.map",
- "^thunk.d.ts",
- "^thunk.js",
- "^thunk.js.map",
- "^tovnode.d.ts",
- "^tovnode.js",
- "^tovnode.js.map",
- "^vnode.d.ts",
- "^vnode.js",
- "^vnode.js.map"
- ]
-}
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
deleted file mode 100644
index 609d01a..0000000
--- a/.eslintrc.cjs
+++ /dev/null
@@ -1,45 +0,0 @@
-module.exports = {
- extends: 'standard-with-typescript',
- parserOptions: {
- project: [
- './src/package/tsconfig.json',
- './src/test/tsconfig.json',
- ]
- },
- plugins: [
- 'markdown',
- ],
- overrides: [
- {
- files: ['**/*.md'],
- processor: 'markdown/markdown'
- },
- {
- files: ['**/*.md/*.@(mjs|ts)'],
- rules: {
- 'no-undef': 'off',
- 'no-unused-expressions': 'off',
- 'no-unused-vars': 'off',
- },
- }
- ],
- rules: {
- 'import/newline-after-import': 'error',
- 'max-statements-per-line': 'error',
- 'no-var': 'error',
- '@typescript-eslint/no-non-null-assertion': 'off',
- '@typescript-eslint/consistent-type-definitions': 'off',
- '@typescript-eslint/explicit-function-return-type': 'off',
- '@typescript-eslint/no-unnecessary-type-assertion': 'off',
- '@typescript-eslint/no-unused-expressions': 'off',
- '@typescript-eslint/prefer-optional-chain': 'off',
- '@typescript-eslint/prefer-includes': 'off',
- '@typescript-eslint/prefer-nullish-coalescing': 'off',
- '@typescript-eslint/no-dynamic-delete': 'off',
- '@typescript-eslint/restrict-plus-operands': 'off',
- '@typescript-eslint/strict-boolean-expressions': 'off',
- '@typescript-eslint/method-signature-style': 'off',
- 'comma-dangle': ['error', 'only-multiline'],
- 'no-mixed-operators': 'off',
- }
-}
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..1c52fec
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,63 @@
+module.exports = {
+ root: true,
+ parser: "@typescript-eslint/parser",
+ plugins: ["@typescript-eslint"],
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:markdown/recommended",
+ "plugin:import/recommended",
+ "plugin:import/typescript",
+ "prettier",
+ ],
+ env: {
+ browser: true,
+ node: false,
+ },
+ overrides: [
+ {
+ files: ["*.ts", "*.tsx"],
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ project: ["./tsconfig.json", "test/tsconfig.json"],
+ },
+ extends: [
+ "plugin:@typescript-eslint/recommended-requiring-type-checking",
+ ],
+ rules: {
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-unsafe-member-access": "off",
+ "@typescript-eslint/no-unsafe-assignment": "off",
+ "@typescript-eslint/no-unsafe-call": "off",
+ "@typescript-eslint/no-unsafe-return": "off",
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/explicit-module-boundary-types": "off",
+ },
+ },
+ {
+ files: ["test/**/*.ts", "test/unit/*.tsx"],
+ env: {
+ browser: true,
+ node: true,
+ },
+ },
+ {
+ files: ["*.js"],
+ excludedFiles: ["examples/**"],
+ extends: ["plugin:node/recommended"],
+ env: {
+ node: true,
+ browser: false,
+ },
+ rules: {
+ "@typescript-eslint/no-var-requires": "off",
+ },
+ },
+ ],
+ rules: {
+ "max-statements-per-line": "error",
+ "no-var": "error",
+ "import/newline-after-import": "error",
+ "import/no-default-export": "error",
+ },
+};
diff --git a/.github/workflows/steps.yml b/.github/workflows/steps.yml
index 1a24fe5..b7126d0 100644
--- a/.github/workflows/steps.yml
+++ b/.github/workflows/steps.yml
@@ -1,26 +1,21 @@
name: CI
-on: pull_request
+on:
+ pull_request:
+ push:
+ branches:
+ - main
jobs:
ci:
runs-on: ubuntu-latest
- environment: ci
steps:
- uses: actions/checkout@v2
- - name: Turnstyle
- uses: softprops/turnstyle@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Read .nvmrc
- run: echo ::set-output name=node-version::$(cat .nvmrc)
- id: nvm
- - uses: actions/setup-node@v2
- with:
- node-version: ${{ steps.nvm.outputs.node-version }}
+
- run: npm ci
- - run: npx run-s test docs check-clean
+
+ - run: npm run test:ci
env:
BROWSER_STACK_USERNAME: ${{ secrets.BROWSER_STACK_USERNAME }}
BROWSER_STACK_ACCESS_KEY: ${{ secrets. BROWSER_STACK_ACCESS_KEY }}
diff --git a/.gitignore b/.gitignore
index 414dc93..70b189a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,88 +9,7 @@
## Package artifacts
-/build/package/tsconfig.tsbuildinfo
-
-/build/package/h.d.ts
-/build/package/h.js
-/build/package/h.js.map
-/build/package/helpers/attachto.d.ts
-/build/package/helpers/attachto.js
-/build/package/helpers/attachto.js.map
-/build/package/hooks.d.ts
-/build/package/hooks.js
-/build/package/hooks.js.map
-/build/package/htmldomapi.d.ts
-/build/package/htmldomapi.js
-/build/package/htmldomapi.js.map
-/build/package/init.d.ts
-/build/package/init.js
-/build/package/init.js.map
-/build/package/is.d.ts
-/build/package/is.js
-/build/package/is.js.map
-/build/package/jsx-global.d.ts
-/build/package/jsx-global.js
-/build/package/jsx-global.js.map
-/build/package/jsx.d.ts
-/build/package/jsx.js
-/build/package/jsx.js.map
-/build/package/modules/attributes.d.ts
-/build/package/modules/attributes.js
-/build/package/modules/attributes.js.map
-/build/package/modules/class.d.ts
-/build/package/modules/class.js
-/build/package/modules/class.js.map
-/build/package/modules/dataset.d.ts
-/build/package/modules/dataset.js
-/build/package/modules/dataset.js.map
-/build/package/modules/eventlisteners.d.ts
-/build/package/modules/eventlisteners.js
-/build/package/modules/eventlisteners.js.map
-/build/package/modules/hero.d.ts
-/build/package/modules/hero.js
-/build/package/modules/hero.js.map
-/build/package/modules/module.d.ts
-/build/package/modules/module.js
-/build/package/modules/module.js.map
-/build/package/modules/props.d.ts
-/build/package/modules/props.js
-/build/package/modules/props.js.map
-/build/package/modules/style.d.ts
-/build/package/modules/style.js
-/build/package/modules/style.js.map
-/build/package/thunk.d.ts
-/build/package/thunk.js
-/build/package/thunk.js.map
-/build/package/tovnode.d.ts
-/build/package/tovnode.js
-/build/package/tovnode.js.map
-/build/package/vnode.d.ts
-/build/package/vnode.js
-/build/package/vnode.js.map
-
-# Test artifacts
-
-/build/test/benchmark/core.js
-/build/test/benchmark/core.js.map
-/build/test/unit/attachto.js
-/build/test/unit/attachto.js.map
-/build/test/unit/attributes.js
-/build/test/unit/attributes.js.map
-/build/test/unit/core.js
-/build/test/unit/core.js.map
-/build/test/unit/dataset.js
-/build/test/unit/dataset.js.map
-/build/test/unit/eventlisteners.js
-/build/test/unit/eventlisteners.js.map
-/build/test/unit/htmldomapi.js
-/build/test/unit/htmldomapi.js.map
-/build/test/unit/jsx.js
-/build/test/unit/jsx.js.map
-/build/test/unit/style.js
-/build/test/unit/style.js.map
-/build/test/unit/thunk.js
-/build/test/unit/thunk.js.map
+/build/
## Test bundle artifacts
diff --git a/.husky/.gitignore b/.husky/.gitignore
index c9cdc63..31354ec 100644
--- a/.husky/.gitignore
+++ b/.husky/.gitignore
@@ -1 +1 @@
-_
\ No newline at end of file
+_
diff --git a/.husky/commit-msg b/.husky/commit-msg
index d2dca3b..5101a23 100755
--- a/.husky/commit-msg
+++ b/.husky/commit-msg
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
-npx commitlint --config commitlint.config.json --edit $1
+npm exec commithelper -- check --file $1 --fix
diff --git a/.husky/pre-commit b/.husky/pre-commit
index b642e23..b4a36dd 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
-npm exec -- npm-run-all -s docs check-clean test
+npm exec -- lint-staged
diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg
new file mode 100755
index 0000000..d8861c9
--- /dev/null
+++ b/.husky/prepare-commit-msg
@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+exec < /dev/tty && npm exec commithelper -- prompt --file $1
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..7053dc1
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1 @@
+/coverage/
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..fbf9e2c
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,3 @@
+build/
+node_modules/
+coverage/
diff --git a/.remarkignore b/.remarkignore
deleted file mode 100644
index 20b126a..0000000
--- a/.remarkignore
+++ /dev/null
@@ -1 +0,0 @@
-/CHANGELOG.md
diff --git a/.versionrc.json b/.versionrc.json
deleted file mode 100644
index 4d05dd6..0000000
--- a/.versionrc.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "skip": {
- "tag": true
- }
-}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ee72619..4f3ce36 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,7 +5,7 @@
"javascriptreact",
"markdown",
"typescript",
- "typescriptreact",
+ "typescriptreact"
],
"eslint.options.ignorePath": ".gitignore"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c65e49..425c233 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,116 +4,109 @@ All notable changes to this project will be documented in this file. See [standa
## [2.1.0](https://github.com/snabbdom/snabbdom/compare/v2.0.0...v2.1.0) (2020-09-14)
-
### Features
-* **eventlisteners:** add types for VNode in listener ([63b1b6c](https://github.com/snabbdom/snabbdom/commit/63b1b6c22e49d06b1fb509a14d321ec19f324bb5)), closes [#796](https://github.com/snabbdom/snabbdom/issues/796)
-* **eventlisteners:** relax custom event listener type ([15ce059](https://github.com/snabbdom/snabbdom/commit/15ce059e2b5e80d1975168fff2d2a44f71bd5cbb)), closes [#850](https://github.com/snabbdom/snabbdom/issues/850)
+- **eventlisteners:** add types for VNode in listener ([63b1b6c](https://github.com/snabbdom/snabbdom/commit/63b1b6c22e49d06b1fb509a14d321ec19f324bb5)), closes [#796](https://github.com/snabbdom/snabbdom/issues/796)
+- **eventlisteners:** relax custom event listener type ([15ce059](https://github.com/snabbdom/snabbdom/commit/15ce059e2b5e80d1975168fff2d2a44f71bd5cbb)), closes [#850](https://github.com/snabbdom/snabbdom/issues/850)
## [2.0.0](https://github.com/snabbdom/snabbdom/compare/v1.0.1...v2.0.0) (2020-09-10)
-
### ⚠ BREAKING CHANGES
-* **eventlisteners:** loaded/carrying event listeners are no longer supported.
+- **eventlisteners:** loaded/carrying event listeners are no longer supported.
### Features
-* **eventlisteners:** add missing mult. listeners type ([5a89efe](https://github.com/snabbdom/snabbdom/commit/5a89efe01580d50f15649c19a444745867c5c0d4)), closes [#794](https://github.com/snabbdom/snabbdom/issues/794)
-* **eventlisteners:** remove loaded listeners feature ([6e0ff8e](https://github.com/snabbdom/snabbdom/commit/6e0ff8e8141c70891e55e41a3107d6d4de0bc754)), closes [#802](https://github.com/snabbdom/snabbdom/issues/802) [#802](https://github.com/snabbdom/snabbdom/issues/802)
-
+- **eventlisteners:** add missing mult. listeners type ([5a89efe](https://github.com/snabbdom/snabbdom/commit/5a89efe01580d50f15649c19a444745867c5c0d4)), closes [#794](https://github.com/snabbdom/snabbdom/issues/794)
+- **eventlisteners:** remove loaded listeners feature ([6e0ff8e](https://github.com/snabbdom/snabbdom/commit/6e0ff8e8141c70891e55e41a3107d6d4de0bc754)), closes [#802](https://github.com/snabbdom/snabbdom/issues/802) [#802](https://github.com/snabbdom/snabbdom/issues/802)
### Bug Fixes
-* **deps:** add regenertor-runtime to devDeps ([2a2964c](https://github.com/snabbdom/snabbdom/commit/2a2964c3eb47cd2f5a7ae88f49b2afe9ea299d7e)), closes [#813](https://github.com/snabbdom/snabbdom/issues/813)
-* **docs:** gitter badge url ([7e19849](https://github.com/snabbdom/snabbdom/commit/7e198493c11f6d4afa8b03d727083d661e85ec0e))
-* **examples:** example import paths ([8111f62](https://github.com/snabbdom/snabbdom/commit/8111f6234a70840673412da6cd37a726a7c839f8)), closes [#761](https://github.com/snabbdom/snabbdom/issues/761)
-* **examples:** totalHeight 0 on remove last element reorder animation ([afa77c0](https://github.com/snabbdom/snabbdom/commit/afa77c04d4ab959a5f2bb5853e5dd821c744843f))
-* **package:** remove directories field ([c7a2a93](https://github.com/snabbdom/snabbdom/commit/c7a2a93f5a2ed63bd76130e5e3d3769a9f1c1c58))
-* **package:** update urls paldepind -> snabbdom ([f94185a](https://github.com/snabbdom/snabbdom/commit/f94185a5bbb31018af48b77449e74f58339fe404)), closes [#775](https://github.com/snabbdom/snabbdom/issues/775)
+- **deps:** add regenertor-runtime to devDeps ([2a2964c](https://github.com/snabbdom/snabbdom/commit/2a2964c3eb47cd2f5a7ae88f49b2afe9ea299d7e)), closes [#813](https://github.com/snabbdom/snabbdom/issues/813)
+- **docs:** gitter badge url ([7e19849](https://github.com/snabbdom/snabbdom/commit/7e198493c11f6d4afa8b03d727083d661e85ec0e))
+- **examples:** example import paths ([8111f62](https://github.com/snabbdom/snabbdom/commit/8111f6234a70840673412da6cd37a726a7c839f8)), closes [#761](https://github.com/snabbdom/snabbdom/issues/761)
+- **examples:** totalHeight 0 on remove last element reorder animation ([afa77c0](https://github.com/snabbdom/snabbdom/commit/afa77c04d4ab959a5f2bb5853e5dd821c744843f))
+- **package:** remove directories field ([c7a2a93](https://github.com/snabbdom/snabbdom/commit/c7a2a93f5a2ed63bd76130e5e3d3769a9f1c1c58))
+- **package:** update urls paldepind -> snabbdom ([f94185a](https://github.com/snabbdom/snabbdom/commit/f94185a5bbb31018af48b77449e74f58339fe404)), closes [#775](https://github.com/snabbdom/snabbdom/issues/775)
### [1.0.1](https://github.com/paldepind/snabbdom/compare/v1.0.0...v1.0.1) (2020-06-18)
-
### User facing changes
-* **package:** fix ./snabbdom related files and exports fields errors ([89b917b](https://github.com/paldepind/snabbdom/commit/89b917bb3f3f8986390e3e400327a9087533d928))
+- **package:** fix ./snabbdom related files and exports fields errors ([89b917b](https://github.com/paldepind/snabbdom/commit/89b917bb3f3f8986390e3e400327a9087533d928))
## [1.0.0](https://github.com/paldepind/snabbdom/compare/v0.7.4...v1.0.0) (2020-06-18)
-
### ⚠ BREAKING CHANGES
-* **exports:** The main export path, 'snabbdom' was replaced with
-the export path 'snabbdom/init'. This new export path includes only
-the named export `init`.
-* **exports:** No default exports exist. All exports are named.
-* **exports:** the import path `snabbdom/snabbdom.bundle` is removed.
-* **typescript:** Types exported by this package have re-declared
-the global `Element.setAttribute` and `Element.setAttributeNS` to
-accept `number` and `boolean` for the `value` parameter. This
-change removes that re-declaration and thus the only valid value is
-`string`. If your code provides `number` and/or `boolean`, then it
-may now fail to compile.
-* **props:** props module does not attempt to delete node
-properties. This may affect you if you are using the props module
-to add non-native (custom) properties to DOM nodes. Instead, it is
-recommended to use _data-* attributes_.
-https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
-* CommonJS modules are no longer provided.
-* import paths in ES modules include file name
-extensions.
-* Compiled to ES2015 (was ES5).
-* UMD bundles are no longer provided.
-
+- **exports:** The main export path, 'snabbdom' was replaced with
+ the export path 'snabbdom/init'. This new export path includes only
+ the named export `init`.
+- **exports:** No default exports exist. All exports are named.
+- **exports:** the import path `snabbdom/snabbdom.bundle` is removed.
+- **typescript:** Types exported by this package have re-declared
+ the global `Element.setAttribute` and `Element.setAttributeNS` to
+ accept `number` and `boolean` for the `value` parameter. This
+ change removes that re-declaration and thus the only valid value is
+ `string`. If your code provides `number` and/or `boolean`, then it
+ may now fail to compile.
+- **props:** props module does not attempt to delete node
+ properties. This may affect you if you are using the props module
+ to add non-native (custom) properties to DOM nodes. Instead, it is
+ recommended to use _data-\* attributes_.
+ https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
+- CommonJS modules are no longer provided.
+- import paths in ES modules include file name
+ extensions.
+- Compiled to ES2015 (was ES5).
+- UMD bundles are no longer provided.
### Internal changes
-* **commitlint:** add type auto and scope deps for renovate ([b56a0ac](https://github.com/paldepind/snabbdom/commit/b56a0ac796a3c27644f8332278a7cbb9d24a95c6))
-* **commitlint:** fix and enable in CI ([f8cf5cc](https://github.com/paldepind/snabbdom/commit/f8cf5ccba402cbbf6982da681db8707fd12fc8d4)), closes [#662](https://github.com/paldepind/snabbdom/issues/662)
-* **deps:** update dependency @typescript-eslint/eslint-plugin to v3.3.0 ([9448e42](https://github.com/paldepind/snabbdom/commit/9448e4267cf077890deb0deb32c3200e4d19a213))
-* **deps:** update dependency tsconfigs to v5 ([eb1ec8c](https://github.com/paldepind/snabbdom/commit/eb1ec8c280544a322fc9844c255b8ec5c8e004c6))
-* **deps:** update dependency typescript to v3.9.5 ([5e24b20](https://github.com/paldepind/snabbdom/commit/5e24b20a52a8c20ed82e3fc7d20977262016731a))
-* **docs:** lint code examples ([41cb359](https://github.com/paldepind/snabbdom/commit/41cb3596e8898399545f02ff8205a1d45f62f391))
-* **eslint:** lint cjs files ([d581217](https://github.com/paldepind/snabbdom/commit/d58121755f4e2da50ad82e52818b66333ae10a37))
-* **format:** sort file lists ([e77615b](https://github.com/paldepind/snabbdom/commit/e77615b16bd60fbd1963528a2c46e7dfbbb77e0e)), closes [#673](https://github.com/paldepind/snabbdom/issues/673)
-* **git:** ignore each test artifact specifically ([b34e9a9](https://github.com/paldepind/snabbdom/commit/b34e9a9d3a8096c2c5cd7eebeafba0e52ed08a75))
-* **package:** consistent values in files field ([6fe56f8](https://github.com/paldepind/snabbdom/commit/6fe56f8538f6e0073d458d7a8e21c8d469c0a9df)), closes [#672](https://github.com/paldepind/snabbdom/issues/672)
-* **relic:** remove @types/assert ([2846189](https://github.com/paldepind/snabbdom/commit/28461899bdce0c2134dca92298e40c1ecf7be363))
-* **typescript:** package and tests are two projects ([8a71211](https://github.com/paldepind/snabbdom/commit/8a71211b4a38616c9d90bc9214e116d1b3e869b5))
-* **vscode:** eslint.validate short forms ([ba3e85b](https://github.com/paldepind/snabbdom/commit/ba3e85bf90f77254fad08435d484e19f836c6783))
-* **vscode:** use workspace typescript ([eabbd2f](https://github.com/paldepind/snabbdom/commit/eabbd2f056b40e5e9376ccf94c9a6f9177bd020a))
-
+- **commitlint:** add type auto and scope deps for renovate ([b56a0ac](https://github.com/paldepind/snabbdom/commit/b56a0ac796a3c27644f8332278a7cbb9d24a95c6))
+- **commitlint:** fix and enable in CI ([f8cf5cc](https://github.com/paldepind/snabbdom/commit/f8cf5ccba402cbbf6982da681db8707fd12fc8d4)), closes [#662](https://github.com/paldepind/snabbdom/issues/662)
+- **deps:** update dependency @typescript-eslint/eslint-plugin to v3.3.0 ([9448e42](https://github.com/paldepind/snabbdom/commit/9448e4267cf077890deb0deb32c3200e4d19a213))
+- **deps:** update dependency tsconfigs to v5 ([eb1ec8c](https://github.com/paldepind/snabbdom/commit/eb1ec8c280544a322fc9844c255b8ec5c8e004c6))
+- **deps:** update dependency typescript to v3.9.5 ([5e24b20](https://github.com/paldepind/snabbdom/commit/5e24b20a52a8c20ed82e3fc7d20977262016731a))
+- **docs:** lint code examples ([41cb359](https://github.com/paldepind/snabbdom/commit/41cb3596e8898399545f02ff8205a1d45f62f391))
+- **eslint:** lint cjs files ([d581217](https://github.com/paldepind/snabbdom/commit/d58121755f4e2da50ad82e52818b66333ae10a37))
+- **format:** sort file lists ([e77615b](https://github.com/paldepind/snabbdom/commit/e77615b16bd60fbd1963528a2c46e7dfbbb77e0e)), closes [#673](https://github.com/paldepind/snabbdom/issues/673)
+- **git:** ignore each test artifact specifically ([b34e9a9](https://github.com/paldepind/snabbdom/commit/b34e9a9d3a8096c2c5cd7eebeafba0e52ed08a75))
+- **package:** consistent values in files field ([6fe56f8](https://github.com/paldepind/snabbdom/commit/6fe56f8538f6e0073d458d7a8e21c8d469c0a9df)), closes [#672](https://github.com/paldepind/snabbdom/issues/672)
+- **relic:** remove @types/assert ([2846189](https://github.com/paldepind/snabbdom/commit/28461899bdce0c2134dca92298e40c1ecf7be363))
+- **typescript:** package and tests are two projects ([8a71211](https://github.com/paldepind/snabbdom/commit/8a71211b4a38616c9d90bc9214e116d1b3e869b5))
+- **vscode:** eslint.validate short forms ([ba3e85b](https://github.com/paldepind/snabbdom/commit/ba3e85bf90f77254fad08435d484e19f836c6783))
+- **vscode:** use workspace typescript ([eabbd2f](https://github.com/paldepind/snabbdom/commit/eabbd2f056b40e5e9376ccf94c9a6f9177bd020a))
### User facing changes
-* **docs:** enable eslint rule array-bracket-spacing ([77e54e9](https://github.com/paldepind/snabbdom/commit/77e54e9105394d4e6d21647a38adfb80ea567ee2))
-* **docs:** enable eslint rule import/first ([17cf7ae](https://github.com/paldepind/snabbdom/commit/17cf7ae931185d8ab1ac1e4f8b7042677e03db8d))
-* **docs:** enable eslint rule import/newline-after-import ([cd3a5cf](https://github.com/paldepind/snabbdom/commit/cd3a5cf17ee33c738d17adcb78a8c254e96653b9))
-* **docs:** enable eslint rule indent ([e2861bb](https://github.com/paldepind/snabbdom/commit/e2861bb1bd68c63c99c30907bb331c21f27cb248))
-* **docs:** enable eslint rule key-spacing ([349b686](https://github.com/paldepind/snabbdom/commit/349b686bd8cfc24a2845fbab62081a15e5b42d0f))
-* **docs:** enable eslint rule max-statements-per-line ([a128a23](https://github.com/paldepind/snabbdom/commit/a128a23ac3182677d10d1979213c92dcf04294ea))
-* **docs:** enable eslint rule no-multi-spaces ([8179381](https://github.com/paldepind/snabbdom/commit/8179381a775acea73d0064c77d643944cf684947)), closes [#692](https://github.com/paldepind/snabbdom/issues/692)
-* **docs:** enable eslint rule object-curly-spacing ([8b8fbd5](https://github.com/paldepind/snabbdom/commit/8b8fbd5e34fdc3a99ce67635cc44f5ef9e3cf30c))
-* **docs:** enable eslint rule quote-props ([37512fe](https://github.com/paldepind/snabbdom/commit/37512fe8ee02cf374cf3d9a62c0f6e3203be2f28))
-* **docs:** enable eslint rule quotes ([2d455b5](https://github.com/paldepind/snabbdom/commit/2d455b52dcabc2f8e52082536e635a66e98eb650))
-* **docs:** enable eslint rule semi ([f4e7885](https://github.com/paldepind/snabbdom/commit/f4e7885663e645aeb728470d5e1f159365f94f1b))
-* **docs:** enable eslint rule space-before-blocks ([9f2d2d7](https://github.com/paldepind/snabbdom/commit/9f2d2d7a1687c7169dff775724a811e1dd7ccd8b))
-* **docs:** enable eslint rule space-before-function-paren ([23e7b87](https://github.com/paldepind/snabbdom/commit/23e7b87c64b5d587acae5ce7bd899ec0d071958e))
-* **docs:** enable eslint rules object-*-newline ([9a45b5b](https://github.com/paldepind/snabbdom/commit/9a45b5b22aba0fbed97431e99268a173995de4a1))
-* **docs:** fix wrong module import paths ([3b6baee](https://github.com/paldepind/snabbdom/commit/3b6baee049f44cbc55cc2b0131c2c551e9c1b452)), closes [#691](https://github.com/paldepind/snabbdom/issues/691)
-* **docs:** provide a release changelog ([616df35](https://github.com/paldepind/snabbdom/commit/616df35909f1d639d562418ea32122625104b00c)), closes [#670](https://github.com/paldepind/snabbdom/issues/670)
-* **exports:** main export provided ([3becd84](https://github.com/paldepind/snabbdom/commit/3becd84cc1dcfb84e2ee292eab18aae36e415040)), closes [#682](https://github.com/paldepind/snabbdom/issues/682)
-* **exports:** only named exports ([fefd141](https://github.com/paldepind/snabbdom/commit/fefd141f5f3567bb6dccbd6c43ce81f285f985bd)), closes [#522](https://github.com/paldepind/snabbdom/issues/522) [#523](https://github.com/paldepind/snabbdom/issues/523)
-* **exports:** relative values in exports field ([187088e](https://github.com/paldepind/snabbdom/commit/187088ee0ebfaed2e84a992bdde50d207131ec29)), closes [#674](https://github.com/paldepind/snabbdom/issues/674)
-* **exports:** remove package.json main field ([3122eec](https://github.com/paldepind/snabbdom/commit/3122eec9b98ffdf52fd31ceb2ced17c219e25042)), closes [#680](https://github.com/paldepind/snabbdom/issues/680)
-* **exports:** remove the /snabbdom.bundle path ([c862993](https://github.com/paldepind/snabbdom/commit/c8629933599b3fdf3ea774f3ce67517908b79d8d))
-* **exports:** replaced main export path with init ([09f2d1c](https://github.com/paldepind/snabbdom/commit/09f2d1ca5a16fd0b402209d90e58b97998efacef)), closes [#522](https://github.com/paldepind/snabbdom/issues/522)
-* **package:** no module field ([2b30e25](https://github.com/paldepind/snabbdom/commit/2b30e25f0d261d2d7f37127bda0c235b0a5acf57)), closes [#681](https://github.com/paldepind/snabbdom/issues/681)
-* **props:** do not attempt to delete node properties ([6f316c1](https://github.com/paldepind/snabbdom/commit/6f316c141b43ccb1c2c355ab8d0c499984154ef1)), closes [#623](https://github.com/paldepind/snabbdom/issues/623) [#283](https://github.com/paldepind/snabbdom/issues/283) [#415](https://github.com/paldepind/snabbdom/issues/415) [#307](https://github.com/paldepind/snabbdom/issues/307) [#151](https://github.com/paldepind/snabbdom/issues/151) [#416](https://github.com/paldepind/snabbdom/issues/416)
-* **typescript:** do not redeclare Element.setAttribute(NS) ([0620b5e](https://github.com/paldepind/snabbdom/commit/0620b5eda03cd124d4bd743660cb376b0d75a0a3)), closes [#615](https://github.com/paldepind/snabbdom/issues/615)
-* do not provide UMD bundles ([8e24bbf](https://github.com/paldepind/snabbdom/commit/8e24bbf016ff5cc0afb2759ec2e4b745921ee453)), closes [#498](https://github.com/paldepind/snabbdom/issues/498) [#514](https://github.com/paldepind/snabbdom/issues/514) [#481](https://github.com/paldepind/snabbdom/issues/481)
-* only esm and correct import paths ([dad44f0](https://github.com/paldepind/snabbdom/commit/dad44f0d632d344ca13ee8430d941c26a53d5c2a)), closes [#516](https://github.com/paldepind/snabbdom/issues/516) [#437](https://github.com/paldepind/snabbdom/issues/437) [#263](https://github.com/paldepind/snabbdom/issues/263)
+- **docs:** enable eslint rule array-bracket-spacing ([77e54e9](https://github.com/paldepind/snabbdom/commit/77e54e9105394d4e6d21647a38adfb80ea567ee2))
+- **docs:** enable eslint rule import/first ([17cf7ae](https://github.com/paldepind/snabbdom/commit/17cf7ae931185d8ab1ac1e4f8b7042677e03db8d))
+- **docs:** enable eslint rule import/newline-after-import ([cd3a5cf](https://github.com/paldepind/snabbdom/commit/cd3a5cf17ee33c738d17adcb78a8c254e96653b9))
+- **docs:** enable eslint rule indent ([e2861bb](https://github.com/paldepind/snabbdom/commit/e2861bb1bd68c63c99c30907bb331c21f27cb248))
+- **docs:** enable eslint rule key-spacing ([349b686](https://github.com/paldepind/snabbdom/commit/349b686bd8cfc24a2845fbab62081a15e5b42d0f))
+- **docs:** enable eslint rule max-statements-per-line ([a128a23](https://github.com/paldepind/snabbdom/commit/a128a23ac3182677d10d1979213c92dcf04294ea))
+- **docs:** enable eslint rule no-multi-spaces ([8179381](https://github.com/paldepind/snabbdom/commit/8179381a775acea73d0064c77d643944cf684947)), closes [#692](https://github.com/paldepind/snabbdom/issues/692)
+- **docs:** enable eslint rule object-curly-spacing ([8b8fbd5](https://github.com/paldepind/snabbdom/commit/8b8fbd5e34fdc3a99ce67635cc44f5ef9e3cf30c))
+- **docs:** enable eslint rule quote-props ([37512fe](https://github.com/paldepind/snabbdom/commit/37512fe8ee02cf374cf3d9a62c0f6e3203be2f28))
+- **docs:** enable eslint rule quotes ([2d455b5](https://github.com/paldepind/snabbdom/commit/2d455b52dcabc2f8e52082536e635a66e98eb650))
+- **docs:** enable eslint rule semi ([f4e7885](https://github.com/paldepind/snabbdom/commit/f4e7885663e645aeb728470d5e1f159365f94f1b))
+- **docs:** enable eslint rule space-before-blocks ([9f2d2d7](https://github.com/paldepind/snabbdom/commit/9f2d2d7a1687c7169dff775724a811e1dd7ccd8b))
+- **docs:** enable eslint rule space-before-function-paren ([23e7b87](https://github.com/paldepind/snabbdom/commit/23e7b87c64b5d587acae5ce7bd899ec0d071958e))
+- **docs:** enable eslint rules object-\*-newline ([9a45b5b](https://github.com/paldepind/snabbdom/commit/9a45b5b22aba0fbed97431e99268a173995de4a1))
+- **docs:** fix wrong module import paths ([3b6baee](https://github.com/paldepind/snabbdom/commit/3b6baee049f44cbc55cc2b0131c2c551e9c1b452)), closes [#691](https://github.com/paldepind/snabbdom/issues/691)
+- **docs:** provide a release changelog ([616df35](https://github.com/paldepind/snabbdom/commit/616df35909f1d639d562418ea32122625104b00c)), closes [#670](https://github.com/paldepind/snabbdom/issues/670)
+- **exports:** main export provided ([3becd84](https://github.com/paldepind/snabbdom/commit/3becd84cc1dcfb84e2ee292eab18aae36e415040)), closes [#682](https://github.com/paldepind/snabbdom/issues/682)
+- **exports:** only named exports ([fefd141](https://github.com/paldepind/snabbdom/commit/fefd141f5f3567bb6dccbd6c43ce81f285f985bd)), closes [#522](https://github.com/paldepind/snabbdom/issues/522) [#523](https://github.com/paldepind/snabbdom/issues/523)
+- **exports:** relative values in exports field ([187088e](https://github.com/paldepind/snabbdom/commit/187088ee0ebfaed2e84a992bdde50d207131ec29)), closes [#674](https://github.com/paldepind/snabbdom/issues/674)
+- **exports:** remove package.json main field ([3122eec](https://github.com/paldepind/snabbdom/commit/3122eec9b98ffdf52fd31ceb2ced17c219e25042)), closes [#680](https://github.com/paldepind/snabbdom/issues/680)
+- **exports:** remove the /snabbdom.bundle path ([c862993](https://github.com/paldepind/snabbdom/commit/c8629933599b3fdf3ea774f3ce67517908b79d8d))
+- **exports:** replaced main export path with init ([09f2d1c](https://github.com/paldepind/snabbdom/commit/09f2d1ca5a16fd0b402209d90e58b97998efacef)), closes [#522](https://github.com/paldepind/snabbdom/issues/522)
+- **package:** no module field ([2b30e25](https://github.com/paldepind/snabbdom/commit/2b30e25f0d261d2d7f37127bda0c235b0a5acf57)), closes [#681](https://github.com/paldepind/snabbdom/issues/681)
+- **props:** do not attempt to delete node properties ([6f316c1](https://github.com/paldepind/snabbdom/commit/6f316c141b43ccb1c2c355ab8d0c499984154ef1)), closes [#623](https://github.com/paldepind/snabbdom/issues/623) [#283](https://github.com/paldepind/snabbdom/issues/283) [#415](https://github.com/paldepind/snabbdom/issues/415) [#307](https://github.com/paldepind/snabbdom/issues/307) [#151](https://github.com/paldepind/snabbdom/issues/151) [#416](https://github.com/paldepind/snabbdom/issues/416)
+- **typescript:** do not redeclare Element.setAttribute(NS) ([0620b5e](https://github.com/paldepind/snabbdom/commit/0620b5eda03cd124d4bd743660cb376b0d75a0a3)), closes [#615](https://github.com/paldepind/snabbdom/issues/615)
+- do not provide UMD bundles ([8e24bbf](https://github.com/paldepind/snabbdom/commit/8e24bbf016ff5cc0afb2759ec2e4b745921ee453)), closes [#498](https://github.com/paldepind/snabbdom/issues/498) [#514](https://github.com/paldepind/snabbdom/issues/514) [#481](https://github.com/paldepind/snabbdom/issues/481)
+- only esm and correct import paths ([dad44f0](https://github.com/paldepind/snabbdom/commit/dad44f0d632d344ca13ee8430d941c26a53d5c2a)), closes [#516](https://github.com/paldepind/snabbdom/issues/516) [#437](https://github.com/paldepind/snabbdom/issues/437) [#263](https://github.com/paldepind/snabbdom/issues/263)
## [v0.7.2] - 2018-09-02
@@ -121,7 +114,7 @@ extensions.
- Improvements to TypeScript types #364. Thanks to @gfmio.
- In some cases and browsers the style module would cause elements to not be removed correctly #367. Thanks to @jvanbruegge for fixing this tricky bug.
-
+
## [v0.7.0] - 2017-07-27
## Breaking change
@@ -144,50 +137,52 @@ The example above will result in the HTML: `
`. Even if `bar
Previously `h("input", { attrs: { required: 0 } })` would result in the HTML `` since `required` was a know boolean attribute and `0` is falsey. Per the new behavior the HTML will be ``. To accomidate for the change always give boolean values for boolean attributes.
## Bugfixes
+
- `toVNode` now handles `DocumentFragment` which makes it possible to patch into a fragment. #320. Thanks to @staltz.
- Custom boolean attributes are handled correctly. #314. Thanks to @caridy.
-- Type improvement. `VNode` key property can be `undefined` #290. Thanks to @yarom82.
+- Type improvement. `VNode` key property can be `undefined` #290. Thanks to @yarom82.
- Data attributes are checked for existence before deleting. Old behavior caused error in Safari. #313. Thanks to @FeliciousX.
## Performance improvements
- New handling of boolean attributes. #314. Thanks to @caridy.
-
+
## [v0.6.9] - 2017-05-19
## Bug fixes
- Fix style delayed and remove to be optional in TypeScript, https://github.com/snabbdom/snabbdom/issues/295
-
+
## [v0.6.8] - 2017-05-16
## Bug fixes
-- Fix error when class is set by vdom selector in SVG, https://github.com/snabbdom/snabbdom/issues/217. Thanks to @caesarsol
-- Fix hyperscript to support undefined or null children in TypeScript, https://github.com/snabbdom/snabbdom/issues/226. Thanks to @ornicar
-- Fix thunk function so it is not called redundantly, https://github.com/snabbdom/snabbdom/pull/273. Thanks to @caesarsol
-- Improve TypeScript types of VNode props, https://github.com/snabbdom/snabbdom/issues/264 and https://github.com/snabbdom/snabbdom/issues/264. Thanks to @mightyiam
+- Fix error when class is set by vdom selector in SVG, https://github.com/snabbdom/snabbdom/issues/217. Thanks to @caesarsol
+- Fix hyperscript to support undefined or null children in TypeScript, https://github.com/snabbdom/snabbdom/issues/226. Thanks to @ornicar
+- Fix thunk function so it is not called redundantly, https://github.com/snabbdom/snabbdom/pull/273. Thanks to @caesarsol
+- Improve TypeScript types of VNode props, https://github.com/snabbdom/snabbdom/issues/264 and https://github.com/snabbdom/snabbdom/issues/264. Thanks to @mightyiam
- Fix toVNode() for comment nodes, lacking some fields, https://github.com/snabbdom/snabbdom/pull/266. Thanks to @staltz
## Performance improvements
-- Improvement for attribute patching, https://github.com/snabbdom/snabbdom/issues/257. Thanks to @diervo
-
+- Improvement for attribute patching, https://github.com/snabbdom/snabbdom/issues/257. Thanks to @diervo
+
## [v0.6.6] - 2017-03-07
## Bug fixes
+
- The attributes module sets boolean attributes correctly according to the specificaiton. https://github.com/snabbdom/snabbdom/issues/254. Thanks to @PerWiklander for reporting the bug.
-
+
## [v0.6.5] - 2017-02-25
This is a patch version with a few bug fixes.
## Bug fixes
-- Fix `toVNode()` to handle text nodes correctly, https://github.com/snabbdom/snabbdom/issues/252. Thanks to @Steelfish
+
+- Fix `toVNode()` to handle text nodes correctly, https://github.com/snabbdom/snabbdom/issues/252. Thanks to @Steelfish
- Fix dataset module to support old browsers, such as IE10. Thanks @staltz
-- Fix "create element" workflow to align with "update element" workflow, https://github.com/snabbdom/snabbdom/pull/234. Thanks @caridy
+- Fix "create element" workflow to align with "update element" workflow, https://github.com/snabbdom/snabbdom/pull/234. Thanks @caridy
-
## [v0.6.4] - 2017-02-09
This version adds some features such as support for comment nodes and better server-side/client-side rendering collaboration, besides some bug fixes.
@@ -198,13 +193,13 @@ This version adds some features such as support for comment nodes and better ser
Example:
-``` js
-h('!', 'Will show as a comment')
+```js
+h("!", "Will show as a comment");
```
will be rendered on the DOM as
-``` html
+```html
```
@@ -214,31 +209,31 @@ Useful for client-side rendering over existing HTML that was rendered server-sid
Example:
-``` js
-import {toVNode} from 'snabbdom/tovnode'
+```js
+import { toVNode } from "snabbdom/tovnode";
// ...
-patch(toVNode(element), vnode)
+patch(toVNode(element), vnode);
```
Will deep-convert the `element` to a VNode, this way allowing existing HTML to not be ignored by the patch process.
## Bug fixes
-- Fix compatibility issue of String.prototype.startsWith in the Style Module. https://github.com/snabbdom/snabbdom/pull/228 Thanks to @zhulongzheng
-- Support for `null`/`undefined` children without crashing. https://github.com/snabbdom/snabbdom/issues/226 Thanks to @nunocastromartins
-
+- Fix compatibility issue of String.prototype.startsWith in the Style Module. https://github.com/snabbdom/snabbdom/pull/228 Thanks to @zhulongzheng
+- Support for `null`/`undefined` children without crashing. https://github.com/snabbdom/snabbdom/issues/226 Thanks to @nunocastromartins
+
## [v0.6.3] - 2017-01-16
## Bugfixes
-- Fix the export of the `Module` interface for TypeScript projects depending on snabbdom.
-
+- Fix the export of the `Module` interface for TypeScript projects depending on snabbdom.
+
## [v0.6.2] - 2017-01-16
## Bugfixes
-- Fix the export of the `Hooks` interface for TypeScript projects depending on snabbdom.
-
+- Fix the export of the `Hooks` interface for TypeScript projects depending on snabbdom.
+
## [v0.6.1] - 2017-01-05
The biggest change in this release is that the Snabbdom source code has been ported to TypeScript. The work has been primarily done by @staltz. This brings much improved support for using Snabbdom in TypeScript projects.
@@ -246,11 +241,13 @@ The biggest change in this release is that the Snabbdom source code has been por
**Note**: This release contains breaking changes. See below.
## New features
+
- Complete TypeScript support. Thanks to @staltz.
- Support for CSS variables. #195. Thanks to @jlesquembre.
- Allow `h(sel, data, node)` and `h(sel, node)` shortcut notations in the `h` function. #196. That is, instead of `h('div', [child])` one can now do `h('div', child)`. Thanks to @AlexGalays.
## Bugfixes
+
- Fix custom element creation when tag name begins with 'svg'. #213. Thanks to @tdumitrescu.
- Fix bug related to updating one child with same key but different selector. #188. Thanks to @zhulongzheng.
- Strings can be used as children inside SVG elements. #208. Thanks to @jbucaran and @jbucaran.
@@ -260,18 +257,16 @@ The biggest change in this release is that the Snabbdom source code has been por
The TypeScript rewrite uses the `import` and `export` features introduced in ECMAScript 2015. Unfortunately the ES imports have no analogy to the CommonJS pattern of setting `module.exports`. This means that the Snabbdom modules that previously used this feature now have to be imported in a slightly different way.
-``` js
+```js
var h = require("snabbdom/h"); // The old way
var h = require("snabbdom/h").h; // The new way
var h = require("snabbdom/h").default; // Alternative new way
-var {h} = require("snabbdom/h"); // Using destructuring
+var { h } = require("snabbdom/h"); // Using destructuring
```
-
## [v0.6.0] - 2017-01-05
-Deprecated. Use [version 0.6.1](https://github.com/snabbdom/snabbdom/releases/tag/v0.6.1) instead.
-
+Deprecated. Use [version 0.6.1](https://github.com/snabbdom/snabbdom/releases/tag/v0.6.1) instead.
## v0.5.0 - 2016-05-16
@@ -279,8 +274,7 @@ Deprecated. Use [version 0.6.1](https://github.com/snabbdom/snabbdom/releases/ta
This release contains a new thunk implementation that solves many issues with the old thunk implementation. The thunk API has changed slightly. Please see the [thunks](https://github.com/paldepind/snabbdom#thunks) section in the readme.
-
-[Unreleased]: https://github.com/snabbdom/snabbdom/compare/v0.7.2...HEAD
+[unreleased]: https://github.com/snabbdom/snabbdom/compare/v0.7.2...HEAD
[v0.7.2]: https://github.com/snabbdom/snabbdom/compare/v0.7.0...v0.7.2
[v0.7.0]: https://github.com/snabbdom/snabbdom/compare/v0.6.9...v0.7.0
[v0.6.9]: https://github.com/snabbdom/snabbdom/compare/v0.6.8...v0.6.9
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cc5849b..af4e934 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,32 +2,14 @@
## Making a release
-Make sure you have permission to publish, by running
+You will need a personal GitHub API token (this is used to create the release on GitHub). You can obtain one [here](https://github.com/settings/tokens/new?scopes=repo&description=release-it) (it only needs "repo" access, not "admin" or other scopes).
- npm access ls-collaborators
+Make sure the token is available with an environment variable. It's best to put this in `~/.profile`:
-While on the `master` branch, switch to a new branch, possibly called `release`:
+```sh
+export GITHUB_TOKEN=""
+```
- git switch --create release
- npm run make-release-commit
+If you saved the token to `~/.profile` you will not have to repeat this in the future.
-Create a new pull request from this branch. The name of the pull request possibly identical to the commit message.
-
-"Rebase and merge" the pull request.
-
- git switch master
- git pull
-
-Where `$VERSION` is the new version, run
-
- git tag v$VERSION
-
-For example:
-
- git tag v5.2.4
-
-And then
-
- git push --tags
- npm compile
- npm publish
+Then simply run `npm run release`. This will automatically determine the new version number based on the commit messages, create the commit, tag, github release and publish to npm.
diff --git a/README.md b/README.md
index 514ef18..5fda93a 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
A virtual DOM library with focus on simplicity, modularity, powerful features
and performance.
-* * *
+---
[](https://opensource.org/licenses/MIT)
[](https://travis-ci.org/snabbdom/snabbdom)
@@ -16,7 +16,7 @@ and performance.
Thanks to [Browserstack](https://www.browserstack.com/) for providing access to
their great cross-browser testing tools.
-* * *
+---
## Introduction
@@ -37,112 +37,126 @@ performance, small size and all the features listed below.
## Features
-* Core features
- * About 200 SLOC – you could easily read through the entire core and fully
+- Core features
+ - About 200 SLOC – you could easily read through the entire core and fully
understand how it works.
- * Extendable through modules.
- * A rich set of hooks available, both per vnode and globally for modules,
+ - Extendable through modules.
+ - A rich set of hooks available, both per vnode and globally for modules,
to hook into any part of the diff and patch process.
- * Splendid performance. Snabbdom is among the fastest virtual DOM libraries.
- * Patch function with a function signature equivalent to a reduce/scan
- function. Allows for easier integration with a FRP library.
-* Features in modules
- * `h` function for easily creating virtual DOM nodes.
- * [SVG _just works_ with the `h` helper](#svg).
- * Features for doing complex CSS animations.
- * Powerful event listener functionality.
- * [Thunks](#thunks) to optimize the diff and patch process even further.
-* Third party features
- * JSX support thanks to [snabbdom-pragma](https://github.com/Swizz/snabbdom-pragma).
- * Server-side HTML output provided by [snabbdom-to-html](https://github.com/acstll/snabbdom-to-html).
- * Compact virtual DOM creation with [snabbdom-helpers](https://github.com/krainboltgreene/snabbdom-helpers).
- * Template string support using [snabby](https://github.com/jamen/snabby).
- * Virtual DOM assertion with [snabbdom-looks-like](https://github.com/jvanbruegge/snabbdom-looks-like)
+ - Splendid performance. Snabbdom is among the fastest virtual DOM libraries.
+ - Patch function with a function signature equivalent to a reduce/scan
+ function. Allows for easier integration with a FRP library.
+- Features in modules
+ - `h` function for easily creating virtual DOM nodes.
+ - [SVG _just works_ with the `h` helper](#svg).
+ - Features for doing complex CSS animations.
+ - Powerful event listener functionality.
+ - [Thunks](#thunks) to optimize the diff and patch process even further.
+ - [JSX support, including TypeScript types](#jsx)
+- Third party features
+ - Server-side HTML output provided by [snabbdom-to-html](https://github.com/acstll/snabbdom-to-html).
+ - Compact virtual DOM creation with [snabbdom-helpers](https://github.com/krainboltgreene/snabbdom-helpers).
+ - Template string support using [snabby](https://github.com/jamen/snabby).
+ - Virtual DOM assertion with [snabbdom-looks-like](https://github.com/jvanbruegge/snabbdom-looks-like)
## Example
```mjs
-import { init } from 'snabbdom/init'
-import { classModule } from 'snabbdom/modules/class'
-import { propsModule } from 'snabbdom/modules/props'
-import { styleModule } from 'snabbdom/modules/style'
-import { eventListenersModule } from 'snabbdom/modules/eventlisteners'
-import { h } from 'snabbdom/h' // helper function for creating vnodes
+import {
+ init,
+ classModule,
+ propsModule,
+ styleModule,
+ eventListenersModule,
+ h,
+} from "snabbdom";
-const patch = init([ // Init patch function with chosen modules
+const patch = init([
+ // Init patch function with chosen modules
classModule, // makes it easy to toggle classes
propsModule, // for setting properties on DOM elements
styleModule, // handles styling on elements with support for animations
eventListenersModule, // attaches event listeners
-])
+]);
-const container = document.getElementById('container')
+const container = document.getElementById("container");
-const vnode = h('div#container.two.classes', { on: { click: someFn } }, [
- h('span', { style: { fontWeight: 'bold' } }, 'This is bold'),
- ' and this is just normal text',
- h('a', { props: { href: '/foo' } }, 'I\'ll take you places!')
-])
+const vnode = h("div#container.two.classes", { on: { click: someFn } }, [
+ h("span", { style: { fontWeight: "bold" } }, "This is bold"),
+ " and this is just normal text",
+ h("a", { props: { href: "/foo" } }, "I'll take you places!"),
+]);
// Patch into empty DOM element – this modifies the DOM as a side effect
-patch(container, vnode)
-
-const newVnode = h('div#container.two.classes', { on: { click: anotherEventHandler } }, [
- h('span', { style: { fontWeight: 'normal', fontStyle: 'italic' } }, 'This is now italic type'),
- ' and this is still just normal text',
- h('a', { props: { href: '/bar' } }, 'I\'ll take you places!')
-])
+patch(container, vnode);
+
+const newVnode = h(
+ "div#container.two.classes",
+ { on: { click: anotherEventHandler } },
+ [
+ h(
+ "span",
+ { style: { fontWeight: "normal", fontStyle: "italic" } },
+ "This is now italic type"
+ ),
+ " and this is still just normal text",
+ h("a", { props: { href: "/bar" } }, "I'll take you places!"),
+ ]
+);
// Second `patch` invocation
-patch(vnode, newVnode) // Snabbdom efficiently updates the old view to the new state
+patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
```
## More examples
-* [Animated reordering of elements](http://snabbdom.github.io/snabbdom/examples/reorder-animation/)
-* [Hero transitions](http://snabbdom.github.io/snabbdom/examples/hero/)
-* [SVG Carousel](http://snabbdom.github.io/snabbdom/examples/carousel-svg/)
+- [Animated reordering of elements](http://snabbdom.github.io/snabbdom/examples/reorder-animation/)
+- [Hero transitions](http://snabbdom.github.io/snabbdom/examples/hero/)
+- [SVG Carousel](http://snabbdom.github.io/snabbdom/examples/carousel-svg/)
-* * *
+---
## Table of contents
-* [Core documentation](#core-documentation)
- * [`init`](#init)
- * [`patch`](#patch)
- * [Unmounting](#unmounting)
- * [`snabbdom/h`](#snabbdomh)
- * [`snabbdom/tovnode`](#snabbdomtovnode)
- * [Hooks](#hooks)
- * [Overview](#overview)
- * [Usage](#usage)
- * [The `init` hook](#the-init-hook)
- * [The `insert` hook](#the-insert-hook)
- * [The `remove` hook](#the-remove-hook)
- * [The `destroy` hook](#the-destroy-hook)
- * [Creating modules](#creating-modules)
-* [Modules documentation](#modules-documentation)
- * [The class module](#the-class-module)
- * [The props module](#the-props-module)
- * [The attributes module](#the-attributes-module)
- * [The dataset module](#the-dataset-module)
- * [The style module](#the-style-module)
- * [Custom properties (CSS variables)](#custom-properties-css-variables)
- * [Delayed properties](#delayed-properties)
- * [Set properties on `remove`](#set-properties-on-remove)
- * [Set properties on `destroy`](#set-properties-on-destroy)
- * [The eventlisteners module](#the-eventlisteners-module)
-* [SVG](#svg)
- * [Classes in SVG Elements](#classes-in-svg-elements)
-* [Thunks](#thunks)
-* [Virtual Node](#virtual-node)
- * [sel : String](#sel--string)
- * [data : Object](#data--object)
- * [children : Array](#children--arrayvnode)
- * [text : string](#text--string)
- * [elm : Element](#elm--element)
- * [key : string | number](#key--string--number)
-* [Structuring applications](#structuring-applications)
-* [Common errors](#common-errors)
-* [Opportunity for community feedback](#opportunity-for-community-feedback)
+- [Core documentation](#core-documentation)
+ - [`init`](#init)
+ - [`patch`](#patch)
+ - [Unmounting](#unmounting)
+ - [`h`](#h)
+ - [`tovnode`](#tovnode)
+ - [Hooks](#hooks)
+ - [Overview](#overview)
+ - [Usage](#usage)
+ - [The `init` hook](#the-init-hook)
+ - [The `insert` hook](#the-insert-hook)
+ - [The `remove` hook](#the-remove-hook)
+ - [The `destroy` hook](#the-destroy-hook)
+ - [Creating modules](#creating-modules)
+- [Modules documentation](#modules-documentation)
+ - [The class module](#the-class-module)
+ - [The props module](#the-props-module)
+ - [The attributes module](#the-attributes-module)
+ - [The dataset module](#the-dataset-module)
+ - [The style module](#the-style-module)
+ - [Custom properties (CSS variables)](#custom-properties-css-variables)
+ - [Delayed properties](#delayed-properties)
+ - [Set properties on `remove`](#set-properties-on-remove)
+ - [Set properties on `destroy`](#set-properties-on-destroy)
+ - [The eventlisteners module](#the-eventlisteners-module)
+- [SVG](#svg)
+ - [Classes in SVG Elements](#classes-in-svg-elements)
+- [Thunks](#thunks)
+- [JSX](#jsx)
+ - [TypeScript](#typescript)
+ - [Babel](#babel)
+- [Virtual Node](#virtual-node)
+ - [sel : String](#sel--string)
+ - [data : Object](#data--object)
+ - [children : Array](#children--arrayvnode)
+ - [text : string](#text--string)
+ - [elm : Element](#elm--element)
+ - [key : string | number](#key--string--number)
+- [Structuring applications](#structuring-applications)
+- [Common errors](#common-errors)
+- [Opportunity for community feedback](#opportunity-for-community-feedback)
## Core documentation
@@ -157,10 +171,9 @@ takes a list of modules and returns a `patch` function that uses the
specified set of modules.
```mjs
-import { classModule } from 'snabbdom/modules/class'
-import { styleModule } from 'snabbdom/modules/style'
+import { classModule, styleModule } from "snabbdom";
-const patch = init([classModule, styleModule])
+const patch = init([classModule, styleModule]);
```
### `patch`
@@ -181,7 +194,7 @@ performant architecture. This also avoids the creation of a new old
vnode tree.
```mjs
-patch(oldVnode, newVnode)
+patch(oldVnode, newVnode);
```
#### Unmounting
@@ -189,53 +202,65 @@ patch(oldVnode, newVnode)
While there is no API specifically for removing a VNode tree from its mount point element, one way of almost achieving this is providing a comment VNode as the second argument to `patch`, such as:
```mjs
-patch(oldVnode, h('!', { hooks: { post: () => { /* patch complete */ } } }))
+patch(
+ oldVnode,
+ h("!", {
+ hooks: {
+ post: () => {
+ /* patch complete */
+ },
+ },
+ })
+);
```
Of course, then there is still a single comment node at the mount point.
-### `snabbdom/h`
+### `h`
-It is recommended that you use `snabbdom/h` to create vnodes. `h` accepts a
+It is recommended that you use `h` to create vnodes. It accepts a
tag/selector as a string, an optional data object and an optional string or
array of children.
```mjs
-import { h } from 'snabbdom/h'
+import { h } from "snabbdom";
-const vnode = h('div', { style: { color: '#000' } }, [
- h('h1', 'Headline'),
- h('p', 'A paragraph'),
-])
+const vnode = h("div", { style: { color: "#000" } }, [
+ h("h1", "Headline"),
+ h("p", "A paragraph"),
+]);
```
-### `snabbdom/tovnode`
+### `tovnode`
-Converts a DOM node into a virtual node. Especially good for patching over an pre-existing,
+Converts a DOM node into a virtual node. Especially good for patching over an pre-existing,
server-side generated content.
```mjs
-import { init } from 'snabbdom/init'
-import { classModule } from 'snabbdom/modules/class'
-import { propsModule } from 'snabbdom/modules/props'
-import { styleModule } from 'snabbdom/modules/style'
-import { eventListenersModule } from 'snabbdom/modules/eventlisteners'
-import { h } from 'snabbdom/h' // helper function for creating vnodes
-import { toVNode } from 'snabbdom/tovnode'
+import {
+ init,
+ classModule,
+ propsModule,
+ styleModule,
+ eventListenersModule,
+ h,
+ toVNode,
+} from "snabbdom";
-const patch = init([ // Init patch function with chosen modules
+const patch = init([
+ // Init patch function with chosen modules
classModule, // makes it easy to toggle classes
propsModule, // for setting properties on DOM elements
styleModule, // handles styling on elements with support for animations
eventListenersModule, // attaches event listeners
-])
+]);
-const newVNode = h('div', { style: { color: '#000' } }, [
- h('h1', 'Headline'),
- h('p', 'A paragraph'),
-])
+const newVNode = h("div", { style: { color: "#000" } }, [
+ h("h1", "Headline"),
+ h("p", "A paragraph"),
+]);
-patch(toVNode(document.querySelector('.container')), newVNode)
+patch(toVNode(document.querySelector(".container")), newVNode);
```
### Hooks
@@ -247,18 +272,18 @@ desired points in the life of a virtual node.
#### Overview
-| Name | Triggered when | Arguments to callback |
-| - | - | - |
-| `pre` | the patch process begins | none |
-| `init` | a vnode has been added | `vnode` |
-| `create` | a DOM element has been created based on a vnode | `emptyVnode, vnode` |
-| `insert` | an element has been inserted into the DOM | `vnode` |
-| `prepatch` | an element is about to be patched | `oldVnode, vnode` |
-| `update` | an element is being updated | `oldVnode, vnode` |
-| `postpatch` | an element has been patched | `oldVnode, vnode` |
-| `destroy` | an element is directly or indirectly being removed | `vnode` |
-| `remove` | an element is directly being removed from the DOM | `vnode, removeCallback` |
-| `post` | the patch process is done | none |
+| Name | Triggered when | Arguments to callback |
+| ----------- | -------------------------------------------------- | ----------------------- |
+| `pre` | the patch process begins | none |
+| `init` | a vnode has been added | `vnode` |
+| `create` | a DOM element has been created based on a vnode | `emptyVnode, vnode` |
+| `insert` | an element has been inserted into the DOM | `vnode` |
+| `prepatch` | an element is about to be patched | `oldVnode, vnode` |
+| `update` | an element is being updated | `oldVnode, vnode` |
+| `postpatch` | an element has been patched | `oldVnode, vnode` |
+| `destroy` | an element is directly or indirectly being removed | `vnode` |
+| `remove` | an element is directly being removed from the DOM | `vnode, removeCallback` |
+| `post` | the patch process is done | none |
The following hooks are available for modules: `pre`, `create`,
`update`, `destroy`, `remove`, `post`.
@@ -273,12 +298,14 @@ To use hooks, pass them as an object to `hook` field of the data
object argument.
```mjs
-h('div.row', {
+h("div.row", {
key: movie.rank,
hook: {
- insert: (vnode) => { movie.elmHeight = vnode.elm.offsetHeight }
- }
-})
+ insert: (vnode) => {
+ movie.elmHeight = vnode.elm.offsetHeight;
+ },
+ },
+});
```
#### The `init` hook
@@ -319,10 +346,10 @@ To see the difference between this hook and the `remove` hook,
consider an example.
```mjs
-const vnode1 = h('div', [h('div', [h('span', 'Hello')])])
-const vnode2 = h('div', [])
-patch(container, vnode1)
-patch(vnode1, vnode2)
+const vnode1 = h("div", [h("div", [h("span", "Hello")])]);
+const vnode2 = h("div", []);
+patch(container, vnode1);
+patch(vnode1, vnode2);
```
Here `destroy` is triggered for both the inner `div` element _and_ the
@@ -345,8 +372,8 @@ const myModule = {
},
update: function (oldVnode, vnode) {
// invoked whenever a virtual node is updated
- }
-}
+ },
+};
```
With this mechanism you can easily augment the behaviour of Snabbdom.
@@ -365,7 +392,7 @@ object should map class names to booleans that indicates whether or
not the class should stay or go on the vnode.
```mjs
-h('a', { class: { active: true, selected: false } }, 'Toggle')
+h("a", { class: { active: true, selected: false } }, "Toggle");
```
### The props module
@@ -373,7 +400,7 @@ h('a', { class: { active: true, selected: false } }, 'Toggle')
Allows you to set properties on DOM elements.
```mjs
-h('a', { props: { href: '/foo' } }, 'Go to Foo')
+h("a", { props: { href: "/foo" } }, "Go to Foo");
```
Properties can only be set. Not removed. Even though browsers allow addition and
@@ -389,7 +416,7 @@ instead. Perhaps via [the dataset module](#the-dataset-module).
Same as props, but set attributes instead of properties on DOM elements.
```mjs
-h('a', { attrs: { href: '/foo' } }, 'Go to Foo')
+h("a", { attrs: { href: "/foo" } }, "Go to Foo");
```
Attributes are added and updated using `setAttribute`. In case of an
@@ -412,7 +439,7 @@ the DOM element.
Allows you to set custom data attributes (`data-*`) on DOM elements. These can then be accessed with the [HTMLElement.dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset) property.
```mjs
-h('button', { dataset: { action: 'reset' } }, 'Reset')
+h("button", { dataset: { action: "reset" } }, "Reset");
```
### The style module
@@ -421,9 +448,17 @@ The style module is for making your HTML look slick and animate smoothly. At
its core it allows you to set CSS properties on elements.
```mjs
-h('span', {
- style: { border: '1px solid #bada55', color: '#c0ffee', fontWeight: 'bold' }
-}, 'Say my name, and every colour illuminates')
+h(
+ "span",
+ {
+ style: {
+ border: "1px solid #bada55",
+ color: "#c0ffee",
+ fontWeight: "bold",
+ },
+ },
+ "Say my name, and every colour illuminates"
+);
```
Note that the style module does not remove style attributes if they
@@ -431,9 +466,13 @@ are removed as properties from the style object. To remove a style,
you should instead set it to the empty string.
```mjs
-h('div', {
- style: { position: shouldFollow ? 'fixed' : '' }
-}, 'I, I follow, I follow you')
+h(
+ "div",
+ {
+ style: { position: shouldFollow ? "fixed" : "" },
+ },
+ "I, I follow, I follow you"
+);
```
#### Custom properties (CSS variables)
@@ -442,9 +481,13 @@ CSS custom properties (aka CSS variables) are supported, they must be prefixed
with `--`
```mjs
-h('div', {
- style: { '--warnColor': 'yellow' }
-}, 'Warning')
+h(
+ "div",
+ {
+ style: { "--warnColor": "yellow" },
+ },
+ "Warning"
+);
```
#### Delayed properties
@@ -453,9 +496,17 @@ You can specify properties as being delayed. Whenever these properties
change, the change is not applied until after the next frame.
```mjs
-h('span', {
- style: { opacity: '0', transition: 'opacity 1s', delayed: { opacity: '1' } }
-}, 'Imma fade right in!')
+h(
+ "span",
+ {
+ style: {
+ opacity: "0",
+ transition: "opacity 1s",
+ delayed: { opacity: "1" },
+ },
+ },
+ "Imma fade right in!"
+);
```
This makes it easy to declaratively animate the entry of elements.
@@ -470,13 +521,17 @@ animated with CSS transitions. Only once all the styles are done
animating will the element be removed from the DOM.
```mjs
-h('span', {
- style: {
- opacity: '1',
- transition: 'opacity 1s',
- remove: { opacity: '0' }
- }
-}, 'It\'s better to fade out than to burn away')
+h(
+ "span",
+ {
+ style: {
+ opacity: "1",
+ transition: "opacity 1s",
+ remove: { opacity: "0" },
+ },
+ },
+ "It's better to fade out than to burn away"
+);
```
This makes it easy to declaratively animate the removal of elements.
@@ -486,13 +541,17 @@ The `all` value of `transition-property` is not supported.
#### Set properties on `destroy`
```mjs
-h('span', {
- style: {
- opacity: '1',
- transition: 'opacity 1s',
- destroy: { opacity: '0' }
- }
-}, 'It\'s better to fade out than to burn away')
+h(
+ "span",
+ {
+ style: {
+ opacity: "1",
+ transition: "opacity 1s",
+ destroy: { opacity: "0" },
+ },
+ },
+ "It's better to fade out than to burn away"
+);
```
The `all` value of `transition-property` is not supported.
@@ -508,10 +567,10 @@ you want to listen to. The function will be called when the event
happens and will be passed the event object that belongs to it.
```mjs
-function clickHandler (ev) {
- console.log('got clicked')
+function clickHandler(ev) {
+ console.log("got clicked");
}
-h('div', { on: { click: clickHandler } })
+h("div", { on: { click: clickHandler } });
```
Very often, however, you're not really interested in the event object
@@ -528,27 +587,27 @@ first element in the array should be a function that will be invoked
with the value in the second element once the event occurs.
```mjs
-function clickHandler (number) {
- console.log('button ' + number + ' was clicked!')
+function clickHandler(number) {
+ console.log("button " + number + " was clicked!");
}
-h('div', [
- h('a', { on: { click: [clickHandler, 1] } }),
- h('a', { on: { click: [clickHandler, 2] } }),
- h('a', { on: { click: [clickHandler, 3] } }),
-])
+h("div", [
+ h("a", { on: { click: [clickHandler, 1] } }),
+ h("a", { on: { click: [clickHandler, 2] } }),
+ h("a", { on: { click: [clickHandler, 3] } }),
+]);
```
Each handler is called not only with the given arguments but also with the current event and vnode appended to the argument list. It also supports using multiple listeners per event by specifying an array of handlers:
```mjs
stopPropagation = function (ev) {
- ev.stopPropagation()
-}
+ ev.stopPropagation();
+};
sendValue = function (func, ev, vnode) {
- func(vnode.elm.value)
-}
+ func(vnode.elm.value);
+};
-h('a', { on: { click: [[sendValue, console.log], stopPropagation] } })
+h("a", { on: { click: [[sendValue, console.log], stopPropagation] } });
```
Snabbdom allows swapping event handlers between renders. This happens without
@@ -565,22 +624,24 @@ In particular, you should **not** do something like this:
```mjs
// Does not work
const sharedHandler = {
- change: function (e) { console.log('you chose: ' + e.target.value) }
-}
-h('div', [
- h('input', {
- props: { type: 'radio', name: 'test', value: '0' },
- on: sharedHandler
+ change: function (e) {
+ console.log("you chose: " + e.target.value);
+ },
+};
+h("div", [
+ h("input", {
+ props: { type: "radio", name: "test", value: "0" },
+ on: sharedHandler,
}),
- h('input', {
- props: { type: 'radio', name: 'test', value: '1' },
- on: sharedHandler
+ h("input", {
+ props: { type: "radio", name: "test", value: "1" },
+ on: sharedHandler,
}),
- h('input', {
- props: { type: 'radio', name: 'test', value: '2' },
- on: sharedHandler
- })
-])
+ h("input", {
+ props: { type: "radio", name: "test", value: "2" },
+ on: sharedHandler,
+ }),
+]);
```
For many such cases, you can use array-based handlers instead (described above).
@@ -589,22 +650,22 @@ Alternatively, simply make sure each node is passed unique `on` values:
```mjs
// Works
const sharedHandler = function (e) {
- console.log('you chose: ' + e.target.value)
-}
-h('div', [
- h('input', {
- props: { type: 'radio', name: 'test', value: '0' },
- on: { change: sharedHandler }
+ console.log("you chose: " + e.target.value);
+};
+h("div", [
+ h("input", {
+ props: { type: "radio", name: "test", value: "0" },
+ on: { change: sharedHandler },
}),
- h('input', {
- props: { type: 'radio', name: 'test', value: '1' },
- on: { change: sharedHandler }
+ h("input", {
+ props: { type: "radio", name: "test", value: "1" },
+ on: { change: sharedHandler },
}),
- h('input', {
- props: { type: 'radio', name: 'test', value: '2' },
- on: { change: sharedHandler }
- })
-])
+ h("input", {
+ props: { type: "radio", name: "test", value: "2" },
+ on: { change: sharedHandler },
+ }),
+]);
```
## SVG
@@ -614,11 +675,20 @@ nodes. SVG elements are automatically created with the appropriate
namespaces.
```mjs
-const vnode = h('div', [
- h('svg', { attrs: { width: 100, height: 100 } }, [
- h('circle', { attrs: { cx: 50, cy: 50, r: 40, stroke: 'green', 'stroke-width': 4, fill: 'yellow' } })
- ])
-])
+const vnode = h("div", [
+ h("svg", { attrs: { width: 100, height: 100 } }, [
+ h("circle", {
+ attrs: {
+ cx: 50,
+ cy: 50,
+ r: 40,
+ stroke: "green",
+ "stroke-width": 4,
+ fill: "yellow",
+ },
+ }),
+ ]),
+]);
```
See also the [SVG example](./examples/svg) and the [SVG Carousel example](./examples/carousel-svg/).
@@ -650,8 +720,8 @@ dealing with immutable data.
Consider a simple function for creating a virtual node based on a number.
```mjs
-function numberView (n) {
- return h('div', 'Number is: ' + n)
+function numberView(n) {
+ return h("div", "Number is: " + n);
}
```
@@ -661,8 +731,8 @@ vnode is wasteful. To avoid the overhead we can use the `thunk` helper
function.
```mjs
-function render (state) {
- return thunk('num', numberView, [state.number])
+function render(state) {
+ return thunk("num", numberView, [state.number]);
}
```
@@ -676,22 +746,77 @@ The view function here is only an example. In practice thunks are only
relevant if you are rendering a complicated view that takes
significant computational time to generate.
+## JSX
+
+### TypeScript
+
+Add the following options to your `tsconfig.json`:
+
+```json
+{
+ "compilerOptions": {
+ "jsx": "react",
+ "jsxFactory": "jsx"
+ }
+}
+```
+
+Then make sure that you use the `.tsx` file extension and import the `jsx` function at the top of the file:
+
+```tsx
+import { jsx, VNode } from "snabbdom";
+
+const node: VNode = (
+
+ I was created with JSX
+
+);
+```
+
+### Babel
+
+Add the following options to your babel configuration:
+
+```json
+{
+ "plugins": [
+ [
+ "@babel/plugin-transform-react-jsx",
+ {
+ "pragma": "jsx"
+ }
+ ]
+ ]
+}
+```
+
+Then make sure that you use the `.jsx` file extension and import the `jsx` function at the top of the file:
+
+```jsx
+import { jsx } from "snabbdom";
+
+const node = (
+