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. -* * * +--- [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://travis-ci.org/snabbdom/snabbdom.svg?branch=master)](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 = ( +
+ I was created with JSX +
+); +``` + ## Virtual Node **Properties** -* [sel](#sel--string) -* [data](#data--object) -* [children](#children--array) -* [text](#text--string) -* [elm](#elm--element) -* [key](#key--string--number) +- [sel](#sel--string) +- [data](#data--object) +- [children](#children--array) +- [text](#text--string) +- [elm](#elm--element) +- [key](#key--string--number) ### sel : String The `.sel` property of a virtual node is the CSS selector passed to -[`h()`](#snabbdomh) during creation. For example: `h('div#container', -{}, [...])` will create a a virtual node which has `div#container` as +[`h()`](#snabbdomh) during creation. For example: `h('div#container', {}, [...])` will create a a virtual node which has `div#container` as its `.sel` property. ### data : Object @@ -708,9 +833,9 @@ For example `h('div', {props: {className: 'container'}}, [...])` will produce a ```mjs ({ props: { - className: 'container' - } -}) + className: "container", + }, +}); ``` as its `.data` object. @@ -728,14 +853,14 @@ create a virtual node with ```mjs [ { - sel: 'h1', + sel: "h1", data: {}, children: undefined, - text: 'Hello, World', + text: "Hello, World", elm: Element, key: undefined, - } -] + }, +]; ``` as its `.children` property. @@ -779,33 +904,33 @@ regards to how you should structure your application. Here are some approaches to building applications with Snabbdom. -* [functional-frontend-architecture](https://github.com/paldepind/functional-frontend-architecture) – +- [functional-frontend-architecture](https://github.com/paldepind/functional-frontend-architecture) – a repository containing several example applications that demonstrates an architecture that uses Snabbdom. -* [Cycle.js](https://cycle.js.org/) – - "A functional and reactive JavaScript framework for cleaner code" - uses Snabbdom -* [Vue.js](http://vuejs.org/) use a fork of snabbdom. -* [scheme-todomvc](https://github.com/amirouche/scheme-todomvc/) build - redux-like architecture on top of snabbdom bindings. -* [kaiju](https://github.com/AlexGalays/kaiju) - +- [Cycle.js](https://cycle.js.org/) – + "A functional and reactive JavaScript framework for cleaner code" + uses Snabbdom +- [Vue.js](http://vuejs.org/) use a fork of snabbdom. +- [scheme-todomvc](https://github.com/amirouche/scheme-todomvc/) build + redux-like architecture on top of snabbdom bindings. +- [kaiju](https://github.com/AlexGalays/kaiju) - Stateful components and observables on top of snabbdom -* [Tweed](https://tweedjs.github.io) – +- [Tweed](https://tweedjs.github.io) – An Object Oriented approach to reactive interfaces. -* [Cyclow](http://cyclow.js.org) - +- [Cyclow](http://cyclow.js.org) - "A reactive frontend framework for JavaScript" uses Snabbdom -* [Tung](https://github.com/Reon90/tung) – +- [Tung](https://github.com/Reon90/tung) – A JavaScript library for rendering html. Tung helps to divide html and JavaScript development. -* [sprotty](https://github.com/theia-ide/sprotty) - "A web-based diagramming framework" uses Snabbdom. -* [Mark Text](https://github.com/marktext/marktext) - "Realtime preview Markdown Editor" build on Snabbdom. -* [puddles](https://github.com/flintinatux/puddles) - +- [sprotty](https://github.com/theia-ide/sprotty) - "A web-based diagramming framework" uses Snabbdom. +- [Mark Text](https://github.com/marktext/marktext) - "Realtime preview Markdown Editor" build on Snabbdom. +- [puddles](https://github.com/flintinatux/puddles) - "Tiny vdom app framework. Pure Redux. No boilerplate." - Built with :heart: on Snabbdom. -* [Backbone.VDOMView](https://github.com/jcbrand/backbone.vdomview) - A [Backbone](http://backbonejs.org/) View with VirtualDOM capability via Snabbdom. -* [Rosmaro Snabbdom starter](https://github.com/lukaszmakuch/rosmaro-snabbdom-starter) - Building user interfaces with state machines and Snabbdom. -* [Pureact](https://github.com/irony/pureact) - "65 lines implementation of React incl Redux and hooks with only one dependency - Snabbdom" -* [Snabberb](https://github.com/tobymao/snabberb) - A minimalistic Ruby framework using [Opal](https://github.com/opal/opal) and Snabbdom for building reactive views. -* [WebCell](https://github.com/EasyWebApp/WebCell) - Web Components engine based on JSX & TypeScript +- [Backbone.VDOMView](https://github.com/jcbrand/backbone.vdomview) - A [Backbone](http://backbonejs.org/) View with VirtualDOM capability via Snabbdom. +- [Rosmaro Snabbdom starter](https://github.com/lukaszmakuch/rosmaro-snabbdom-starter) - Building user interfaces with state machines and Snabbdom. +- [Pureact](https://github.com/irony/pureact) - "65 lines implementation of React incl Redux and hooks with only one dependency - Snabbdom" +- [Snabberb](https://github.com/tobymao/snabberb) - A minimalistic Ruby framework using [Opal](https://github.com/opal/opal) and Snabbdom for building reactive views. +- [WebCell](https://github.com/EasyWebApp/WebCell) - Web Components engine based on JSX & TypeScript Be sure to share it if you're building an application in another way using Snabbdom. @@ -820,40 +945,40 @@ Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node': The reason for this error is reusing of vnodes between patches (see code example), snabbdom stores actual dom nodes inside the virtual dom nodes passed to it as performance improvement, so reusing nodes between patches is not supported. ```mjs -const sharedNode = h('div', {}, 'Selected') -const vnode1 = h('div', [ - h('div', {}, ['One']), - h('div', {}, ['Two']), - h('div', {}, [sharedNode]), -]) -const vnode2 = h('div', [ - h('div', {}, ['One']), - h('div', {}, [sharedNode]), - h('div', {}, ['Three']), -]) -patch(container, vnode1) -patch(vnode1, vnode2) +const sharedNode = h("div", {}, "Selected"); +const vnode1 = h("div", [ + h("div", {}, ["One"]), + h("div", {}, ["Two"]), + h("div", {}, [sharedNode]), +]); +const vnode2 = h("div", [ + h("div", {}, ["One"]), + h("div", {}, [sharedNode]), + h("div", {}, ["Three"]), +]); +patch(container, vnode1); +patch(vnode1, vnode2); ``` You can fix this issue by creating a shallow copy of the object (here with object spread syntax): ```mjs -const vnode2 = h('div', [ - h('div', {}, ['One']), - h('div', {}, [{ ...sharedNode }]), - h('div', {}, ['Three']), -]) +const vnode2 = h("div", [ + h("div", {}, ["One"]), + h("div", {}, [{ ...sharedNode }]), + h("div", {}, ["Three"]), +]); ``` Another solution would be to wrap shared vnodes in a factory function: ```mjs -const sharedNode = () => h('div', {}, 'Selected') -const vnode1 = h('div', [ - h('div', {}, ['One']), - h('div', {}, ['Two']), - h('div', {}, [sharedNode()]), -]) +const sharedNode = () => h("div", {}, "Selected"); +const vnode1 = h("div", [ + h("div", {}, ["One"]), + h("div", {}, ["Two"]), + h("div", {}, [sharedNode()]), +]); ``` ## Opportunity for community feedback diff --git a/browserstack-karma.cjs b/browserstack-karma.cjs deleted file mode 100644 index c821992..0000000 --- a/browserstack-karma.cjs +++ /dev/null @@ -1,101 +0,0 @@ -module.exports = { - // Latest mainstream - BS_Chrome_Current: { - base: 'BrowserStack', - browser: 'chrome', - browser_version: 'latest', - os: 'Windows', - os_version: '10', - }, - BS_Firefox_Current: { - base: 'BrowserStack', - browser: 'firefox', - browser_version: 'latest', - os: 'Windows', - os_version: '10', - }, - BS_Safari_Current: { - base: 'BrowserStack', - browser: 'safari', - browser_version: 'latest', - os: 'OS X', - os_version: 'High Sierra', - }, - BS_Android_8: { - base: 'BrowserStack', - browser: 'Android', - device: 'Google Pixel 2', - os: 'Android', - os_version: '8.0', - real_mobile: true, - }, - - // Older mainstream - /* https://github.com/snabbdom/snabbdom/issues/468 - BS_Chrome_49: { - base: 'BrowserStack', - browser: 'chrome', - browser_version: '49', - os: 'Windows', - os_version: '10', - }, - */ - BS_Firefox_52: { - base: 'BrowserStack', - browser: 'firefox', - browser_version: '52', - os: 'Windows', - os_version: '10', - }, - /* https://github.com/snabbdom/snabbdom/issues/469 - BS_Safari_9: { - base: 'BrowserStack', - browser: 'safari', - browser_version: '9.1', - os: 'OS X', - os_version: 'El Capitan', - }, - */ - - // Misc - BS_Android_4_4: { - base: 'BrowserStack', - device_browser: 'ucbrowser', - device: 'Google Nexus 5', - os: 'Android', - os_version: '4.4', - real_mobile: true, - }, - /* https://github.com/snabbdom/snabbdom/issues/470 - BS_iphone_10: { - base: 'BrowserStack', - browser: 'Mobile Safari', - browser_version: null, - device: 'iPhone 7', - real_mobile: true, - os: 'ios', - os_version: '10.3', - }, - */ - BS_MS_Edge: { - base: 'BrowserStack', - browser: 'edge', - browser_version: 'latest', - os: 'Windows', - os_version: '10', - }, - BS_IE_11: { - base: 'BrowserStack', - browser: 'ie', - browser_version: '11.0', - os: 'Windows', - os_version: '7', - }, - BS_IE_10: { - base: 'BrowserStack', - browser: 'ie', - browser_version: '10.0', - os: 'Windows', - os_version: '7', - }, -} diff --git a/browserstack-karma.js b/browserstack-karma.js new file mode 100644 index 0000000..92dce72 --- /dev/null +++ b/browserstack-karma.js @@ -0,0 +1,89 @@ +module.exports = { + // Latest mainstream + BS_Chrome_Current: { + base: "BrowserStack", + browser: "chrome", + browser_version: "latest", + os: "Windows", + os_version: "10", + }, + BS_Firefox_Current: { + base: "BrowserStack", + browser: "firefox", + browser_version: "latest", + os: "Windows", + os_version: "10", + }, + BS_Safari_Current: { + base: "BrowserStack", + browser: "safari", + browser_version: "latest", + os: "OS X", + os_version: "Big Sur", + }, + BS_Android_8: { + base: "BrowserStack", + browser: "Android", + device: "Google Pixel 2", + os: "Android", + os_version: "8.0", + real_mobile: true, + }, + + // Older mainstream + BS_Chrome_50: { + base: "BrowserStack", + browser: "chrome", + browser_version: "50", + os: "Windows", + os_version: "10", + }, + BS_Firefox_52: { + base: "BrowserStack", + browser: "firefox", + browser_version: "52", + os: "Windows", + os_version: "10", + }, + BS_Safari_10: { + base: "BrowserStack", + browser: "safari", + browser_version: "10.1", + os: "OS X", + os_version: "Sierra", + }, + + // Misc + BS_Android_4_4: { + base: "BrowserStack", + device_browser: "ucbrowser", + device: "Google Nexus 5", + os: "Android", + os_version: "4.4", + real_mobile: true, + }, + BS_iphone_10: { + base: "BrowserStack", + browser: "Mobile Safari", + browser_version: null, + device: "iPhone 7", + real_mobile: true, + os: "ios", + os_version: "10.3", + }, + BS_MS_Edge: { + base: "BrowserStack", + browser: "edge", + browser_version: "latest", + os: "Windows", + os_version: "10", + }, + BS_IE_11: { + base: "BrowserStack", + browser: "ie", + browser_version: "11.0", + os: "Windows", + os_version: "7", + es5: true, + }, +}; diff --git a/commitlint.config.json b/commitlint.config.json deleted file mode 100644 index adea4ab..0000000 --- a/commitlint.config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "extends": [ - "@commitlint/config-conventional" - ], - "rules": { - "scope-empty": [2, "never"], - "scope-enum": [2, "always", [ - "ci", - "commitlint", - "deps", - "docs", - "eslint", - "eventlisteners", - "examples", - "exports", - "format", - "git", - "github", - "karma", - "npm", - "package", - "relic", - "style", - "ttypescript", - "typescript", - "vscode" - ]] - } -} diff --git a/examples/carousel-svg/index.html b/examples/carousel-svg/index.html index d93131d..f916094 100644 --- a/examples/carousel-svg/index.html +++ b/examples/carousel-svg/index.html @@ -1,74 +1,83 @@ - - - - Carousel - - - - -
- + + + + Carousel + + + + +
+ diff --git a/examples/carousel-svg/index.js b/examples/carousel-svg/index.js index 3a2463e..ef91bc9 100644 --- a/examples/carousel-svg/index.js +++ b/examples/carousel-svg/index.js @@ -1,74 +1,119 @@ -import { init } from '../../build/package/init.js' -import { attributesModule } from '../../build/package/modules/attributes.js' -import { styleModule } from '../../build/package/modules/style.js' -import { eventListenersModule } from '../../build/package/modules/eventlisteners.js' -import { h } from '../../build/package/h.js' +import { + init, + attributesModule, + styleModule, + eventListenersModule, + h, +} from "../../build/index.js"; -var patch = init([attributesModule, styleModule, eventListenersModule]) +const patch = init([attributesModule, styleModule, eventListenersModule]); -var vnode +let vnode; -var data = { - degRotation: 0 -} +let data = { + degRotation: 0, +}; -function gRotation () { +function gRotation() { // console.log("gRotation: %s", data.degRotation); - return 'rotate(' + data.degRotation + 'deg)' + return "rotate(" + data.degRotation + "deg)"; } -function triangleClick (id) { - console.log('triangleClick: %s', id) - render() +function triangleClick(id) { + console.log("triangleClick: %s", id); + render(); } -function handleRotate (degs) { - data.degRotation += degs - console.log('handleRotate: %s, %s', degs, data.degRotation) - render() +function handleRotate(degs) { + data.degRotation += degs; + console.log("handleRotate: %s, %s", degs, data.degRotation); + render(); } -function handleReset (degs) { - data.degRotation = degs - console.log('handleReset: %s', degs) - render() +function handleReset(degs) { + data.degRotation = degs; + console.log("handleReset: %s", degs); + render(); } -function render () { - vnode = patch(vnode, view(data)) +function render() { + vnode = patch(vnode, view(data)); } const hTriangle = (id, degRotation) => - h('polygon#' + id, { + h("polygon#" + id, { attrs: { - points: '-50,-88 0,-175 50,-88', - transform: 'rotate(' + degRotation + ')', - 'stroke-width': 3 + points: "-50,-88 0,-175 50,-88", + transform: "rotate(" + degRotation + ")", + "stroke-width": 3, + }, + on: { + click: () => { + triangleClick(id); + }, }, - on: { click: () => { triangleClick(id) } } - }) + }); -const view = (data) => - h('div.view', [ - h('h1', 'Snabbdom SVG Carousel'), - h('svg', { attrs: { width: 380, height: 380, viewBox: [-190, -190, 380, 380] } }, [ - h('g#carousel', - { style: { '-webkit-transform': gRotation(), transform: gRotation() } }, [ - hTriangle('yellow', 0), - hTriangle('green', 60), - hTriangle('magenta', 120), - hTriangle('red', 180), - hTriangle('cyan', 240), - hTriangle('blue', 300) - ]) - ]), - h('button', { on: { click: () => { handleRotate(60) } } }, 'Rotate Clockwise'), - h('button', { on: { click: () => { handleRotate(-60) } } }, 'Rotate Anticlockwise'), - h('button', { on: { click: () => { handleReset(0) } } }, 'Reset') - ]) +const view = () => + h("div.view", [ + h("h1", "Snabbdom SVG Carousel"), + h( + "svg", + { attrs: { width: 380, height: 380, viewBox: [-190, -190, 380, 380] } }, + [ + h( + "g#carousel", + { + style: { "-webkit-transform": gRotation(), transform: gRotation() }, + }, + [ + hTriangle("yellow", 0), + hTriangle("green", 60), + hTriangle("magenta", 120), + hTriangle("red", 180), + hTriangle("cyan", 240), + hTriangle("blue", 300), + ] + ), + ] + ), + h( + "button", + { + on: { + click: () => { + handleRotate(60); + }, + }, + }, + "Rotate Clockwise" + ), + h( + "button", + { + on: { + click: () => { + handleRotate(-60); + }, + }, + }, + "Rotate Anticlockwise" + ), + h( + "button", + { + on: { + click: () => { + handleReset(0); + }, + }, + }, + "Reset" + ), + ]); -window.addEventListener('DOMContentLoaded', () => { - var container = document.getElementById('container') - vnode = patch(container, view(data)) - render() -}) +window.addEventListener("DOMContentLoaded", () => { + const container = document.getElementById("container"); + vnode = patch(container, view(data)); + render(); +}); diff --git a/examples/hero/index.html b/examples/hero/index.html index 6a7bd63..eaeba34 100644 --- a/examples/hero/index.html +++ b/examples/hero/index.html @@ -2,14 +2,18 @@ - + Hero animation