Merge branch 'master' into dispatch-cancelable

pull/7064/head
bluwy 4 years ago
commit 4f9b4d8ee6

1
.gitignore vendored

@ -9,6 +9,7 @@ node_modules
/compiler.*js
/index.*js
/ssr.*js
/action
/internal
/store
/easing

@ -2,12 +2,39 @@
## Unreleased
* Return the context object in `setContext` [#7427](https://github.com/sveltejs/svelte/issues/7427)
* Fix `{@const}` tag not working inside Component when there's no `let:` [#7189](https://github.com/sveltejs/svelte/issues/7189)
* Ignore comments in `{#each}` blocks when containing elements with `animate:` ([#3999](https://github.com/sveltejs/svelte/issues/3999))
* Add a third parameter to the returned function of `createEventDispatcher` that allows passing an object of `{ cancelable: true }` to create a cancelable custom event. The returned function when called will also return a boolean depending on whether the event is cancelled ([#7064](https://github.com/sveltejs/svelte/pull/7064))
## 3.47.0
* Add support for dynamic elements through `<svelte:element>` ([#2324](https://github.com/sveltejs/svelte/issues/2324))
* Miscellaneous variable context fixes in `{@const}` ([#7222](https://github.com/sveltejs/svelte/pull/7222))
* Fix `{#key}` block not being reactive when the key variable is not otherwise used ([#7408](https://github.com/sveltejs/svelte/issues/7408))
* Add `Symbol` as a known global ([#7418](https://github.com/sveltejs/svelte/issues/7418))
## 3.46.6
* Actually include action TypeScript interface in published package ([#7407](https://github.com/sveltejs/svelte/pull/7407))
## 3.46.5
* Add TypeScript interfaces for typing actions ([#6538](https://github.com/sveltejs/svelte/issues/6538))
* Do not generate `unused-export-let` warning inside `<script context="module">` blocks ([#7055](https://github.com/sveltejs/svelte/issues/7055))
* Do not collapse whitespace-only CSS vars ([#7152](https://github.com/sveltejs/svelte/issues/7152))
* Add `aria-description` to the list of allowed ARIA attributes ([#7301](https://github.com/sveltejs/svelte/issues/7301))
* Fix attribute escaping during SSR ([#7327](https://github.com/sveltejs/svelte/issues/7327))
* Prevent `.innerHTML` optimization from being used when `style:` directive is present ([#7386](https://github.com/sveltejs/svelte/issues/7386))
## 3.46.4
* Avoid `maximum call stack size exceeded` errors on large components ([#4694](https://github.com/sveltejs/svelte/issues/4694))
* Keep space in `<pre>` tags or when `preserveWhitespace` is `true`([#6437](https://github.com/sveltejs/svelte/issues/6437), [#4731](https://github.com/sveltejs/svelte/issues/4731))
* Better error message when trying to use style directives on inline components ([#7177](https://github.com/sveltejs/svelte/issues/7177))
* Preserve leading space with `preserveWhitespace: true` ([#4731](https://github.com/sveltejs/svelte/issues/4731))
* Preserve leading space in `<pre>` tags ([#6437](https://github.com/sveltejs/svelte/issues/6437))
* Improve error message when trying to use `style:` directives on inline components ([#7177](https://github.com/sveltejs/svelte/issues/7177))
* Add `FormData` as a known global ([#7199](https://github.com/sveltejs/svelte/pull/7199))
* Mark `css`/`instance`/`module` Ast properties as optional ([#7204](https://github.com/sveltejs/svelte/pull/7204))
* Add a third parameter to the returned function of `createEventDispatcher` that allows passing an object of `{ cancelable: true }` to create a cancelable custom event. The returned function will also return a boolean depending on whether the event is cancelled ([#7064](https://github.com/sveltejs/svelte/pull/7064))
* Mark `css`/`instance`/`module` AST properties as optional in types ([#7204](https://github.com/sveltejs/svelte/pull/7204))
## 3.46.3

@ -15,7 +15,7 @@ There are many ways to contribute to Svelte, and many of them do not involve wri
- Look through the [open issues](https://github.com/sveltejs/svelte/issues). A good starting point would be issues tagged [good first issue](https://github.com/sveltejs/svelte/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). Provide workarounds, ask for clarification, or suggest labels. Help [triage issues](#triaging-issues-and-pull-requests).
- If you find an issue you would like to fix, [open a pull request](#your-first-pull-request).
- Read through our [tutorials](https://svelte.dev/tutorial/basics). If you find anything that is confusing or can be improved, you can make edits by clicking "Edit this chapter" at the bottom left of the tutorial page.
- Take a look at the [features requested](https://github.com/sveltejs/svelte/labels/enhancement) by others in the community and consider opening a pull request if you see something you want to work on.
- Take a look at the [features requested](https://github.com/sveltejs/svelte/labels/feature%20request) by others in the community and consider opening a pull request if you see something you want to work on.
Contributions are very welcome. If you think you need help planning your contribution, please ping us on Discord at [svelte.dev/chat](https://svelte.dev/chat) and let us know you are looking for a bit of help.
@ -67,7 +67,7 @@ Working on your first Pull Request? You can learn how from this free video serie
If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, you can also file an issue with [feature template](https://github.com/sveltejs/svelte/issues/new?template=feature_request.md).
If you're only fixing a bug, it's fine to submit a pull request right away but we still recommend that you file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue.
If you're only fixing a bug, it's fine to submit a pull request right away, but we still recommend that you file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue.
### Sending a pull request

223
package-lock.json generated

@ -1,11 +1,11 @@
{
"name": "svelte",
"version": "3.46.3",
"version": "3.47.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "3.46.3",
"version": "3.47.0",
"license": "MIT",
"devDependencies": {
"@ampproject/remapping": "^0.3.0",
@ -114,28 +114,6 @@
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/@eslint/eslintrc/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@eslint/eslintrc/node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
@ -668,15 +646,19 @@
}
},
"node_modules/ajv": {
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^2.0.1",
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ansi-colors": {
@ -689,9 +671,9 @@
}
},
"node_modules/ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
"dev": true,
"engines": {
"node": ">=6"
@ -1700,9 +1682,9 @@
}
},
"node_modules/eslint/node_modules/ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
@ -1798,12 +1780,6 @@
"node": ">=4"
}
},
"node_modules/eslint/node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/eslint/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -2126,9 +2102,9 @@
]
},
"node_modules/fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/fast-glob": {
@ -3013,9 +2989,9 @@
"dev": true
},
"node_modules/json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
"dev": true
},
"node_modules/json-schema-traverse": {
@ -3049,18 +3025,18 @@
}
},
"node_modules/jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"dev": true,
"engines": [
"node >=0.6.0"
],
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"json-schema": "0.4.0",
"verror": "1.10.0"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/kleur": {
@ -3259,9 +3235,9 @@
}
},
"node_modules/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"node_modules/mkdirp": {
@ -3655,9 +3631,9 @@
}
},
"node_modules/path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/path-type": {
@ -3940,15 +3916,6 @@
"node": ">=8.16.0"
}
},
"node_modules/puppeteer/node_modules/progress": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
"integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/puppeteer/node_modules/ws": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
@ -4627,9 +4594,9 @@
}
},
"node_modules/table/node_modules/ajv": {
"version": "8.6.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz",
"integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==",
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz",
"integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
@ -4657,12 +4624,6 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/table/node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/table/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@ -5047,9 +5008,9 @@
}
},
"node_modules/wide-align/node_modules/ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
"dev": true,
"engines": {
"node": ">=4"
@ -5247,26 +5208,6 @@
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
},
"dependencies": {
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
}
}
},
"@humanwhocodes/config-array": {
@ -5667,12 +5608,12 @@
"dev": true
},
"ajv": {
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
@ -5685,9 +5626,9 @@
"dev": true
},
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
"dev": true
},
"ansi-styles": {
@ -6326,9 +6267,9 @@
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
@ -6399,12 +6340,6 @@
}
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -6825,9 +6760,9 @@
"dev": true
},
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-glob": {
@ -7491,9 +7426,9 @@
"dev": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
"dev": true
},
"json-schema-traverse": {
@ -7524,14 +7459,14 @@
}
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"dev": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"json-schema": "0.4.0",
"verror": "1.10.0"
}
},
@ -7694,9 +7629,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"mkdirp": {
@ -8008,9 +7943,9 @@
"dev": true
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"path-type": {
@ -8235,12 +8170,6 @@
"ws": "^6.1.0"
},
"dependencies": {
"progress": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
"integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
"dev": true
},
"ws": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
@ -8776,9 +8705,9 @@
},
"dependencies": {
"ajv": {
"version": "8.6.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz",
"integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==",
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz",
"integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@ -8799,12 +8728,6 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@ -9135,9 +9058,9 @@
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
"dev": true
},
"string-width": {

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.46.3",
"version": "3.47.0",
"description": "Cybernetically enhanced web apps",
"module": "index.mjs",
"main": "index",
@ -16,7 +16,7 @@
"transition",
"easing",
"motion",
"svelte",
"action",
"README.md"
],
"exports": {
@ -39,6 +39,9 @@
"import": "./compiler.mjs",
"require": "./compiler.js"
},
"./action": {
"types": "./types/runtime/action/index.d.ts"
},
"./animate": {
"types": "./types/runtime/animate/index.d.ts",
"import": "./animate/index.mjs",
@ -110,7 +113,7 @@
"bugs": {
"url": "https://github.com/sveltejs/svelte/issues"
},
"homepage": "https://github.com/sveltejs/svelte#README",
"homepage": "https://svelte.dev",
"devDependencies": {
"@ampproject/remapping": "^0.3.0",
"@rollup/plugin-commonjs": "^11.0.0",

@ -12,7 +12,9 @@ Because of that, getting started with it can be a little bit confusing at first.
## 1. Use the REPL
The [Svelte REPL](/repl) is the easiest way to begin. You can choose from a list of examples to get you started, and tweak them until they do what you want.
The [Svelte REPL](/repl) (Read-Eval-Print Loop) is the easiest way to begin. This is an interactive environment that allows you to modify code and instantly see the result.
You can choose from a list of [examples](/examples/), click the [REPL](/repl) link, and then tweak them until they do what you want.
<aside><p>You'll need to have <a href="https://nodejs.org/">Node.js</a> installed, and know how to use the terminal</p></aside>
@ -31,8 +33,7 @@ npm install
npm run dev
```
This will serve your app on [localhost:5000](http://localhost:5000) and rebuild it with [Rollup](https://rollupjs.org) every time you make a change to the files in `svelte-app/src`.
This will serve your app on [localhost:8080](http://localhost:8080) and rebuild it with [Rollup](https://rollupjs.org) every time you make a change to the files in `svelte-app/src`.
## 2. Use degit
@ -50,7 +51,7 @@ npm install
npm run dev
```
This will create a new project in the `my-svelte-project` directory, install its dependencies, and start a server on http://localhost:5000.
This will create a new project in the `my-svelte-project` directory, install its dependencies, and start a server on http://localhost:8080.
You can find more information about using TypeScript [here](/blog/svelte-and-typescript).

@ -78,7 +78,7 @@ npm run dev
Running the `dev` script starts a program called [Rollup](https://rollupjs.org/guide/en/). Rollup's job is to take your application's source files (so far, just `src/main.js` and `src/App.svelte`), pass them to other programs (including Svelte, in our case) and convert them into the code that will actually run when you open the application in a browser.
Speaking of which, open a browser and navigate to http://localhost:5000. This is your application running on a local *web server* (hence 'localhost') on port 5000.
Speaking of which, open a browser and navigate to http://localhost:8080. This is your application running on a local *web server* (hence 'localhost') on port 8080.
Try changing `src/App.svelte` and saving it. The application will reload with your changes.
@ -99,7 +99,7 @@ Your `public` directory now contains a compressed `bundle.js` file containing yo
npm run start
```
This will run the app on http://localhost:5000.
This will run the app on http://localhost:8080.
## Next steps

@ -24,7 +24,7 @@ npm install
npm run dev -- --open
```
You'll find documentation at [kit.svelte.dev/docs](https://kit.svelte.dev/docs). If you have a [Sapper](https://sapper.svelte.dev) app that you'd like to migrate to SvelteKit, you'll find instructions at [kit.svelte.dev/migrating](https://kit.svelte.dev/migrating).
You'll find documentation at [kit.svelte.dev/docs](https://kit.svelte.dev/docs). If you have a [Sapper](https://sapper.svelte.dev) app that you'd like to migrate to SvelteKit, you'll find instructions at [kit.svelte.dev/docs/migrating](https://kit.svelte.dev/docs/migrating).
The source code is available at [github.com/sveltejs/kit](https://github.com/sveltejs/kit). Issues and pull requests are disabled while we finish getting our house in order, but we'll be making it fully open in the near future.
@ -60,8 +60,8 @@ Using unfinished software to build an app that will be seen by millions of peopl
## The road to 1.0
You can see the list of outstanding issues with the 1.0 milestone on our [issue tracker](https://github.com/sveltejs/kit/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.0). Alongside that work, we plan to upgrade the documentation and add more [adapters](https://kit.svelte.dev/docs#adapters).
You can see the list of outstanding issues with the 1.0 milestone on our [issue tracker](https://github.com/sveltejs/kit/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.0). Alongside that work, we plan to upgrade the documentation and add more [adapters](https://kit.svelte.dev/docs/adapters).
Most importantly though, we need your feedback to help us make the best possible app framework. Try it out, and let us know which pieces are missing.
Many thanks to everyone who has tried SvelteKit out despite the 'here be dragons' warnings and lack of documentation; your back-channel feedback has been invaluable. In particular, I want to acknowledge the work of [GrygrFlzr](https://github.com/GrygrFlzr), who maintained unofficial docs and a fork that added Windows support when we lacked it; and [dominikg](https://github.com/dominikg) whose work on [Svite](https://github.com/svitejs/svite) laid essential groundwork for SvelteKit's Vite integration. Both have now been welcomed onto the team.
Many thanks to everyone who has tried SvelteKit out despite the 'here be dragons' warnings and lack of documentation; your back-channel feedback has been invaluable. In particular, I want to acknowledge the work of [GrygrFlzr](https://github.com/GrygrFlzr), who maintained unofficial docs and a fork that added Windows support when we lacked it; and [dominikg](https://github.com/dominikg) whose work on [Svite](https://github.com/svitejs/svite) laid essential groundwork for SvelteKit's Vite integration. Both have now been welcomed onto the team.

@ -14,10 +14,10 @@ Last week, Svelte Summit blew us away with a mountain of content! [Check out the
## New in SvelteKit
- [kit.svelte.dev](https://kit.svelte.dev/) has a fresh new look and the [SvelteKit Demo Site](https://netlify.demo.svelte.dev/) got a fresh set of paint. Check it out by running `npm init svelte@next`
- You can now use `@sveltejs/adapter-static` to create a single-page app or SPA by specifying a fallback page ([PR](https://github.com/sveltejs/kit/pull/1181), [Docs](https://github.com/sveltejs/kit/tree/master/packages/adapter-static))
- Disable Server-side Rendering (SSR) app-wide or on a page-by-page basis ([PR](https://github.com/sveltejs/kit/pull/713), [Docs](https://kit.svelte.dev/docs#ssr-and-javascript-ssr))
- Error messages thrown during pre-rendering are now much more informative and readable ([PR](https://github.com/sveltejs/kit/pull/1062), [Docs](https://kit.svelte.dev/docs#layouts-error-pages))
- Layouts can now be reset to prevent pages from inheriting the root layout. This is useful if you have a specific layout for a page or i18n variation ([PR](https://github.com/sveltejs/kit/pull/1061), [Docs](https://kit.svelte.dev/docs#layouts-resets))
- `fetch` in SvelteKit code will now use the environment-provided implementation, whenever possible. If `fetch` is unavailable, it will be polyfilled by adapters ([PR](https://github.com/sveltejs/kit/pull/1066), [Docs](https://kit.svelte.dev/docs#loading-input-fetch))
- Disable Server-side Rendering (SSR) app-wide or on a page-by-page basis ([PR](https://github.com/sveltejs/kit/pull/713))
- Error messages thrown during pre-rendering are now much more informative and readable ([PR](https://github.com/sveltejs/kit/pull/1062), [Docs](https://kit.svelte.dev/docs/layouts#error-pages))
- Layouts can now be reset to prevent pages from inheriting the root layout. This is useful if you have a specific layout for a page or i18n variation ([PR](https://github.com/sveltejs/kit/pull/1061), [Docs](https://kit.svelte.dev/docs/layouts#resets))
- `fetch` in SvelteKit code will now use the environment-provided implementation, whenever possible. If `fetch` is unavailable, it will be polyfilled by adapters ([PR](https://github.com/sveltejs/kit/pull/1066), [Docs](https://kit.svelte.dev/docs/loading#input-fetch))
## New in Svelte & Language Tools
- `svelte-preprocess` now supports the "extends" field of the tsconfig.json (4.7.2)

@ -29,8 +29,8 @@ The focus this past month was on continuing to iron out any kinks, with well ove
- SvelteKit will now detect if a prerendered app is trying to access a query parameter and return an error instead of failing silently ([#2104](https://github.com/sveltejs/kit/pull/2104))
- `adapter-node` now lets you [add the Kit middleware to your own server](https://kit.svelte.dev/faq#integrations) for use with other middleware. You can also [add middleware in dev mode](https://kit.svelte.dev/faq#how-do-i-use-x-with-sveltekit-how-do-i-use-middleware) with more improvements to come in this area
- The new [`sequence` helper lets you chain together multiple `handle` calls](https://kit.svelte.dev/docs#modules-sveltejs-kit-hooks)
- A new [`handleError` hook](https://kit.svelte.dev/docs#hooks-handleerror) gives you the option to send data to an error tracking service, or to customise the formatting before printing the error to the console.
- The new [`sequence` helper lets you chain together multiple `handle` calls](https://kit.svelte.dev/docs/modules#sveltejs-kit-hooks)
- A new [`handleError` hook](https://kit.svelte.dev/docs/hooks#handleerror) gives you the option to send data to an error tracking service, or to customise the formatting before printing the error to the console.
- `adapter-node` can now listen on socket path ([#2048](https://github.com/sveltejs/kit/pull/2048))
To see all updates to SvelteKit, check out the [SvelteKit changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).

@ -16,21 +16,21 @@ Let's take a look...
- [AST output is now available in the Svelte REPL](https://svelte.dev/repl/hello-world)
## What's new in SvelteKit
- `inlineStyleThreshold` allows you to specify where inline stylesheets are inserted into the page ([Docs](https://kit.svelte.dev/docs#configuration-inlinestylethreshold), [#2620](https://github.com/sveltejs/kit/pull/2620))
- `beforeNavigate`/`afterNavigate` lifecycle functions lets you add functionality before or after a page navigation ([Docs](https://kit.svelte.dev/docs#modules-$app-navigation), [#3293](https://github.com/sveltejs/kit/pull/3293))
- Platform context can now be passed from adapters ([Docs](https://kit.svelte.dev/docs#adapters-supported-environments-platform-specific-context), [#3429](https://github.com/sveltejs/kit/pull/3429))
- Hooks now have an `ssr` parameter in `resolve` to make it easier to skip SSR, when needed ([Docs](https://kit.svelte.dev/docs#hooks-handle), [#2804](https://github.com/sveltejs/kit/pull/2804))
- `$page.stuff` provides a mechanism for pages to pass data 'upward' to layouts ([Docs](https://kit.svelte.dev/docs#loading-input-stuff), [#3252](https://github.com/sveltejs/kit/pull/3252))
- Fallthrough routes let you specify where to route when an route can't be loaded ([Docs](https://kit.svelte.dev/docs#routing-advanced-fallthrough-routes), [#3217](https://github.com/sveltejs/kit/pull/3217))
- `inlineStyleThreshold` allows you to specify where inline stylesheets are inserted into the page ([Docs](https://kit.svelte.dev/docs/configuration#inlinestylethreshold), [#2620](https://github.com/sveltejs/kit/pull/2620))
- `beforeNavigate`/`afterNavigate` lifecycle functions lets you add functionality before or after a page navigation ([Docs](https://kit.svelte.dev/docs/modules#$app-navigation), [#3293](https://github.com/sveltejs/kit/pull/3293))
- Platform context can now be passed from adapters ([Docs](https://kit.svelte.dev/docs/adapters#supported-environments-platform-specific-context), [#3429](https://github.com/sveltejs/kit/pull/3429))
- Hooks now have an `ssr` parameter in `resolve` to make it easier to skip SSR, when needed ([Docs](https://kit.svelte.dev/docs/hooks#handle), [#2804](https://github.com/sveltejs/kit/pull/2804))
- `$page.stuff` provides a mechanism for pages to pass data 'upward' to layouts ([Docs](https://kit.svelte.dev/docs/loading#input-stuff), [#3252](https://github.com/sveltejs/kit/pull/3252))
- Fallthrough routes let you specify where to route when an route can't be loaded ([Docs](https://kit.svelte.dev/docs/routing#advanced-routing-fallthrough-routes), [#3217](https://github.com/sveltejs/kit/pull/3217))
**New configs**
- Content Security Policy (CSP) is now supported for increased security when using inline javascript or stylesheets ([Docs](https://kit.svelte.dev/docs#configuration-csp), [#3499](https://github.com/sveltejs/kit/pull/3499))
- `kit.routes` config allows you to customise public/private modules during build ([Docs](https://kit.svelte.dev/docs#configuration-routes), [#3576](https://github.com/sveltejs/kit/pull/3576))
- `prerender.createIndexFiles` config lets you prerender index.html files as their subfolder's name ([Docs](https://kit.svelte.dev/docs#configuration-prerender), [#2632](https://github.com/sveltejs/kit/pull/2632))
- HTTP methods can now be overridden using `kit.methodOverride` ([Docs](https://kit.svelte.dev/docs#routing-endpoints-http-method-overrides), [#2989](https://github.com/sveltejs/kit/pull/2989))
- Content Security Policy (CSP) is now supported for increased security when using inline javascript or stylesheets ([Docs](https://kit.svelte.dev/docs/configuration#csp), [#3499](https://github.com/sveltejs/kit/pull/3499))
- `kit.routes` config allows you to customise public/private modules during build ([Docs](https://kit.svelte.dev/docs/configuration#routes), [#3576](https://github.com/sveltejs/kit/pull/3576))
- `prerender.createIndexFiles` config lets you prerender index.html files as their subfolder's name ([Docs](https://kit.svelte.dev/docs/configuration#prerender), [#2632](https://github.com/sveltejs/kit/pull/2632))
- HTTP methods can now be overridden using `kit.methodOverride` ([Docs](https://kit.svelte.dev/docs/routing#endpoints-http-method-overrides), [#2989](https://github.com/sveltejs/kit/pull/2989))
**Config changes**
- `config.kit.hydrate` and `config.kit.router` are now nested under `config.kit.browser` ([Docs](https://kit.svelte.dev/docs#configuration-browser), [3578](https://github.com/sveltejs/kit/pull/3578))
- `config.kit.hydrate` and `config.kit.router` are now nested under `config.kit.browser` ([Docs](https://kit.svelte.dev/docs/configuration#browser), [3578](https://github.com/sveltejs/kit/pull/3578))
**Breaking change**
- use `Request` and `Response` objects in endpoints and hooks ([#3384](https://github.com/sveltejs/kit/pull/3384))

@ -0,0 +1,87 @@
---
title: "What's new in Svelte: March 2022"
description: "Svelte Summit Spring is coming... and page endpoints are here!"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
Just announced: [Svelte Summit Spring](https://www.sveltesummit.com/) will be taking place on April 30, 2022. The 5th Virtual Svelte Conference is [looking for speakers](https://www.sveltesummit.com/#speakers) and [sponsors](https://www.sveltesummit.com/sponsors)... so it's time to dust off those proposals!
Also, some long-requested features were added to SvelteKit this month... including page endpoints! This change in how the `load` function works makes it easier to fetch data required for basic pages, redirect from POST responses and handle 404s and other errors.
More on that and other new features and fixes below!
## What's new in SvelteKit
- The docs are now searchable and multipage with type definitions and hoverable code examples - Check them out at [kit.svelte.dev/docs](https://kit.svelte.dev/docs/)
- Page endpoints significantly decrease the boilerplate needed when loading a page ([Issue](https://github.com/sveltejs/kit/issues/3532), [PR](https://github.com/sveltejs/kit/pull/3679), [Docs](https://kit.svelte.dev/docs/routing#endpoints-page-endpoints))
- Application versioning and update detection support lets you determine what to do when a route fails to load after an app update ([Issue](https://github.com/sveltejs/kit/issues/87), [PR](https://github.com/sveltejs/kit/pull/3412), [Docs](https://kit.svelte.dev/docs/configuration#version))
- A new option in `npm init svelte@next` will now set up Playwright automatically for testing ([PR](https://github.com/sveltejs/kit/pull/4056))
**Breaking Changes**
- The `target` option is no longer available. Instead, the `init` script hydrates its `parentNode` ([#3674](https://github.com/sveltejs/kit/pull/3674))
- App-level types now live in the `App` namespace which allows you to type global types like `Stuff` or `Session` ([#3670](https://github.com/sveltejs/kit/pull/3670))
- `JSONString` is now `JSONValue` ([#3683](https://github.com/sveltejs/kit/pull/3683))
- `createIndexFiles` has been removed — it is now controlled by the `trailingSlash` option ([#3801](https://github.com/sveltejs/kit/pull/3801))
- SvelteKit will no longer exclude root-relative external links from prerendering, which will cause 404s if these URLs are intended to be served by a separate app. Use a custom [`prerender.onError`](https://kit.svelte.dev/docs/configuration#prerender) handler if you need to ignore them ([#3826](https://github.com/sveltejs/kit/pull/3826))
## New in Language Tools
- Accessing properties in markups has been improved in the Svelte language tools ([105.12.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-105.12.0)) - working around some known issues with autocomplete ([#538](https://github.com/sveltejs/language-tools/issues/538) / [#1302](https://github.com/sveltejs/language-tools/issues/1302))
---
## Community Showcase
**Apps & Sites**
- [SvelteStorm](https://github.com/open-source-labs/SvelteStorm) is specifically tailored to provide all of the essential tools a Svelte developer needs to build a Svelte application
- [Supachat](https://github.com/Lleweraf/supachat) is a real-time chat app using Svelte and Supabase
- [Radicle](https://radicle.xyz/) is a peer-to-peer stack for building software together
- [The Making Known](https://the-making-known.com/) is a narrated encounter with posters designed by the Nazi German government to communicate with the occupied nations of Belgium, France, and Luxembourg during the Second World War
- [Svelte Kanban](https://github.com/V-Py/svelte-kanban) is a simple Svelte Kanban made in pure CSS
- [fngrng](https://github.com/nvlgzr/fngrng) is a typing trainer focussed on accuracy over speed
- [Generative grids](https://svelte.dev/repl/873988ce33db43f097c0ca69df57b3ac?version=3.46.4) is a neat little generative SVG grid in a Svelte REPL, with randomly generated color palettes and shapes
- [LifeHash](https://github.com/BlockchainCommons/lifehash.info) is a method of hash visualization that creates beautiful, deterministic icons
- [TypedWebhook.tools](https://typedwebhook.tools/) is a webhook testing tool for checking payloads, with automatic type generation
- [Speedskating](https://github.com/spiegelgraphics/speedskating) is an animation widget to show olympic speedskating runs. Built with Svelte, D3 and regl
- [Web tail](https://github.com/mishankov/web-tail) is a web application to view lines from file on local system or on remote server
Want to work on a SvelteKit site with others? [Contribute to the Svelte Society site](https://github.com/svelte-society/sveltesociety.dev/issues)!
**Learning Resources**
_To Read_
- [Svelte Components as Web Components](https://medium.com/@yesmeno/svelte-components-as-web-components-b400d1253504) by Matias Meno
- [Simple Svelte Routing with Reactive URLs](https://bjornlu.com/blog/simple-svelte-routing-with-reactive-urls) by Bjorn Lu
- [Leveling Up my Sveltekit / Sanity.io Blog Content with Featured Videos and Syntax Highlighting](https://ryanboddy.net/level-up-blog) by Ryan Boddy
- [How This Blog Makes the Most of GitHub](https://paullj.github.io/posts/how-this-blog-makes-the-most-of-github/) by paullj
- [FullStack JWT Auth: Introducing SvelteKit](https://dev.to/sirneij/fullstack-jwt-introducing-sveltekit-3jcn) by John Idogun
- [Svelte-Cubed: Adding Motion to 3D Scenes](https://dev.to/alexwarnes/svelte-cubed-adding-motion-to-3d-scenes-51lo) by Alex Warnes
- [Creating a RSS feed with Sanity and Svelte Kit](https://ghostdev.xyz/posts/creating-a-rss-feed-with-sanity-and-svelte-kit) by GHOST
- [How to use Svelte's style directive](https://geoffrich.net/posts/style-directives/) by Geoff Rich
- [SvelteKit and the "Client pattern"](https://retro.cloud/sveltekit-and-the-client-pattern/) by Julian Laubstein
_To Watch_
- [~~Shadow~~ Page Endpoints In Svelte Kit - Weekly Svelte](https://www.youtube.com/watch?v=PoYPZT7ruqI) by LevelUpTuts
- [Testing For Beginners (Playlist)](https://www.youtube.com/watch?v=y53wwdBr5AI&list=PLA9WiRZ-IS_z7KpqhPELfEMbhAGRwZrzn) by Joy of Code
- [KitQL - The native SvelteKit library for GraphQL](https://www.youtube.com/watch?v=6pH4fnFN70w) by Jean-Yves COUËT
**Libraries, Tools & Components**
- [gosvelte](https://github.com/sachinbhutani/gosvelte) is a proof of concept to serve Svelte-generated pages on GoLang HTTP server with server data being sent as props to svelte components
- [svelte-ethers-store](https://www.npmjs.com/package/svelte-ethers-store) uses the ethers.js library as a collection of readable Svelte stores for Svelte, Sapper or SvelteKit
- [Fluid Grid](https://fluid-grid.com/) is a CSS grid system for future web
- [stirstack](https://github.com/seeReadCode/stirstack) is an opinionated framework that combines Svelte.js, TailwindCSS, InertiaJS and Ruby on Rails
- [OATHqr](https://codeberg.org/vhs/oathqr) helps users create security credentials for use with 2FA/MFA and other OATH-enabled apps. Use it to generate scannable QR codes for one-time password authenticator apps such as Aegis or YubiKey
- [svelte-GridTiles](https://github.com/honeybeeSunshine/svelte-GridTiles) is a drag and drop resizable tiles library built on a responsive grid
- [Miscellaneous Svelte Components](https://github.com/alex-knyaz/Miscellaneous-svelte-components/) is a collection of miscellaneous svelte components alex-knyaz often use in my projects
- [walk-and-graph-svelte-components](https://github.com/j2l/walk-and-graph-svelte-components) is a CLI node script to walk svelte and js files, to draw a beautiful JPG of your dependencies aka "imports"
- [Felte](https://www.npmjs.com/package/felte) is a simple to use form library for Svelte
- [svelte-use-tooltip](https://github.com/untemps/svelte-use-tooltip) is a Svelte action to display a tooltip
- [persistent-svelte-store](https://github.com/omer-g/persistent-svelte-store) is a generic persistent writable store, built from scratch in TypeScript according to the Svelte store contract
What'd we miss? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs) to continue the conversation.
See y'all next month!

@ -0,0 +1,104 @@
---
title: "What's new in Svelte: April 2022"
description: "Goodbye fallthrough routes, hello param validators!"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
This month, we felt a shift in the way SvelteKit handles page properties. The last holdout of the use-cases that required fallthrough routes, validating parameter properties, has been replaced by a more specific solution.
More on that, and what else is new in Svelte, as we dive in...
## What's new in SvelteKit
- Param matchers allow you to check if a url parameter matches before rendering a page - replacing the need for fallthrough routes for this purpose ([Docs](https://kit.svelte.dev/docs/routing#advanced-routing-matching), [#4334](https://github.com/sveltejs/kit/pull/4334))
- Explicit redirects can now be handled directly from endpoints ([#4260](https://github.com/sveltejs/kit/pull/4260))
- `svelte-kit sync` ([#4182](https://github.com/sveltejs/kit/pull/4182)), TypeScript 4.6 ([#4190](https://github.com/sveltejs/kit/pull/4190)) and Vite 2.9 were released - adding non-blocking dependency optimization and experimental CSS source maps in dev mode as well as a number of bug fixes contributed by the SvelteKit team ([#4468](https://github.com/sveltejs/kit/pull/4468))
**New Config Options**
- `outDir` fixes path issues in monorepos and other situations where the desired output directory is outside the project directory ([Docs](https://kit.svelte.dev/docs/configuration#outdir), [#4176](https://github.com/sveltejs/kit/pull/4176))
- `endpointExtensions` prevents files other than .js and .ts files from being treated as endpoints, unless you specify endpointExtensions ([Docs](https://kit.svelte.dev/docs/configuration#endpointextensions), [#4197](https://github.com/sveltejs/kit/pull/4197))
- `prerender.default` lets you prerender every page without having to write `export const prerender = true` in every page file ([Docs](https://kit.svelte.dev/docs/configuration#prerender), [#4192](https://github.com/sveltejs/kit/pull/4192))
**Breaking Changes**
- Fallthrough routes have been removed. For migration tips, check out the PR ([#4330](https://github.com/sveltejs/kit/pull/4330))
- `tabindex="-1"` is only added to `<body>` during navigation ([#4140](https://github.com/sveltejs/kit/pull/4140) and [#4184](https://github.com/sveltejs/kit/pull/4184))
- Adapters are now required to supply a `getClientAddress` function ([#4289](https://github.com/sveltejs/kit/pull/4289))
- `InputProps` and `OutputProps` can now be typed separately in generated `Load` ([#4305](https://github.com/sveltejs/kit/pull/4305))
- The `\$` character is no longer allowed in dynamic parameters ([#4334](https://github.com/sveltejs/kit/pull/4334))
- `svelte-kit package` has been marked as experimental so changes to it after Kit 1.0 will not be considered breaking ([#4164](https://github.com/sveltejs/kit/pull/4164))
## New across the Svelte ecosystem
- Svelte: Lots of new types for TypeScript and Svelte plugin users - including `style:` directives and Svelte Actions (**3.46.4** and **3.46.5**)
- Language Tools: Svelte project files are now importable/findable through references without having them imported in a TS file ([105.13.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-105.13.0))
- Language Tools: Region folding is now supported in html with `<!--#region-->`/`<!--#endregion-->` ([105.13.0](https://github.com/sveltejs/language-tools/releases/tag/extensions-105.13.0))
---
## Community Showcase
**Apps & Sites built with Svelte**
- [Launcher](https://launcher.team/) is an open-source app launcher powered by SvelteKit, Prisma, and Tailwind
- [Paaster](https://paaster.io/) is a secure by default end to end encrypted pastebin built with Svelte, Vite, Typescript, Python, Starlette, rclone & Docker.
- [Simple AF Video Converter](https://github.com/berlyozzy/Simple-AF-Video-Converter) is an Electron wrapper around ffmpeg.wasm to make converting videos between formats easier
- [Streamchaser](https://github.com/streamchaser/streamchaser) seeks to simplify movie, series and documentary search through a centralized entertainment technology platform
- [Svelte Color Picker](https://github.com/V-Py/svelte-material-color-picker) is a simple color picker made with Svelte
- [ConcertMash](https://github.com/mcmxcdev/ConcertMash) is a small website that interacts with the Spotify API and generates new playlists based on the upcoming concerts you're attending
- [Modulus](https://modulus.vision/) is a Design+Code Think Tank conceived with the main mission to evolve design and technology
- [Multiply](https://www.multiply.us/) is an integrated PR and Social agency moving at the speed of culture
- [yia!](https://www.yia.co.nz/) is a Young Innovator Award competition in New Zealand
- [Write to Russia](https://www.writetorussia.org/index) is a community email writing platform to communicate with public `.ru` email addresses
- [Markdown Playground](https://github.com/Petros-K/markdown-playground) is an online playground dedicated for your markdown experiments.
- [RatherMisty](https://rathermisty.com/) is a no frills weather app with weather data from Open-Meteo
- [Minecraft Profile Pic (MCPFP)](https://github.com/MauritsWilke/mcpfp) is a site to generate Minecraft profile pictures with ease
- [WebGL Fluid Simulation](https://github.com/jpaquim/svelte-webgl-fluid-simulation) is a configurable fluid simulation built with Svelte and WebGL
- [This @NobelPeaceOslo exhibition](https://twitter.com/perbyhring/status/1504754949791621120) was built using printed graphics, projected motion graphics, particle animations and generative sound design
Itching to contribute to a modern SvelteKit website? [Help build the Svelte Society site](https://github.com/svelte-society/sveltesociety.dev/issues)!
**Learning Resources**
_To Attend_
- [Svelte Summit: Spring](https://www.sveltesummit.com/) will take place on April 30, 2022! Join us for the 5th virtual Svelte conference on [YouTube](https://www.sveltesummit.com/) and Discord 🍾
_To Read_
- [Svelte(Kit) TypeScript Showcase + general TypeScript tips](https://github.com/ivanhofer/sveltekit-typescript-showcase) by Hofer Ivan
- [Local constants in Svelte with the @const tag](https://geoffrich.net/posts/local-constants/) by Geoff Rich
- [Design Patterns for Building Reusable Svelte Components](https://render.com/blog/svelte-design-patterns) by Eric Liu
- [Svelte is better than React](https://labs.hamy.xyz/posts/svelte-is-better-than-react/) by Hamilton Greene
- [Making Visualizations Literally with Svelte and D3](https://www.connorrothschild.com/post/svelte-and-d3) by Connor Rothschild
- [Coordinating Multiple Elements with Svelte Deferred Transitions](https://imfeld.dev/writing/svelte_deferred_transitions) by Daniel Imfeld
- [Animate on scroll with Svelte Inview - Little Bits](https://dev.to/maciekgrzybek/animate-on-scroll-with-svelte-inview-266f) by Maciek Grzybek
- [Lazy-Loading Firebase with SvelteKit](https://www.captaincodeman.com/lazy-loading-firebase-with-sveltekit) and [HeadlessUI Components with Svelte](https://www.captaincodeman.com/headlessui-components-with-svelte) by Captain Codeman
- [SvelteKit Accessibility Testing: Automated CI A11y Tests](https://rodneylab.com/sveltekit-accessibility-testing/) by Rodney Lab
- [Getting Started with KitQL and GraphCMS](https://scottspence.com/posts/getting-started-with-kitql-and-graphcms) by Scott Spence
- [React ⇆ Svelte Cheatsheet](https://dev.to/joshnuss/react-to-svelte-cheatsheet-1a2a) lists the similarities and differences between the two libraries - by Joshua Nussbaum
_To Watch_
- [Svelte Extravaganza | Async](https://www.youtube.com/watch?v=mT4CLVHgtSg) by pngwn
- [6 Svelte Packages You Should Know](https://www.youtube.com/watch?v=y5SrUKcX_Co) and [Basic React To Svelte Conversion](https://www.youtube.com/watch?v=DiSuwLlhOxs) by LevelUpTuts
- [Page/Shadow Endpoint in SvelteKit](https://www.youtube.com/watch?v=j-9D5UDyVOM) by WebJeda
- [Custom Svelte Store: Higher Order Store](https://www.youtube.com/watch?v=p1aPfVyZ1IY) by lihautan
- [SvelteKit For Beginners (Playlist)](https://www.youtube.com/watch?v=bLBHecY4-ak&list=PLA9WiRZ-IS_zXZZyW4qfj0akvOAtk6MFS) by Joy of Code - follow along with the [blog guide](https://joyofcode.xyz/sveltekit-for-beginners)
- [Fullstack SvelteKit Auth 🔐 with Firebase & Magic Links! 🪄](https://www.youtube.com/watch?v=MAHE4iQgh5Q) by Johnny Magrippis
- [Firebase Authentication in SvelteKit! Full Stack App](https://www.youtube.com/watch?v=N6Y3hqhZvNI) by Ryan Boddy
**Libraries, Tools & Components**
- [SvelTable](https://sveltable.io/) is a feature rich, data table component built with Svelte
- [svelte-cyberComp](https://github.com/Cybersteam00/svelte-cyberComp) is a powerful, lightweight component library written in Svelte and Typescript
- [Flowbite Svelte](https://github.com/shinokada/flowbite-svelte) is an unofficial Flowbite component library for Svelte
- [Svelte-Tide-Project](https://github.com/jbertovic/svelte-tide-project) is a starter template for Svelte frontend apps with Rust Tide backend server
- [Fetch Inject](https://github.com/vhscom/fetch-inject#sveltekit) implements a performance optimization technique for managing asynchronous JavaScript dependencies - now with Svelte support
- [svelte-utterances](https://github.com/shinokada/svelte-utterances) is a lightweight comments widget built on GitHub issues
- [Liquivelte](https://github.com/malipetek/liquivelte-vscode) allows you to create your Shopify theme with Svelte-like components
- [@storyblok/svelte](https://github.com/storyblok/storyblok-svelte) is the Svelte SDK you need to interact with Storyblok API and enable the Real-time Visual Editing Experience
- [@svelte-on-solana/wallet-adapter](https://github.com/svelte-on-solana/wallet-adapter) is a modular TypeScript wallet adapter and UI components for Solana/Anchor applications using SvelteJS as framework
- [svelte-lookat](https://www.npmjs.com/package/svelte-lookat) creates a div which makes all its children follow the mouse cursor or the user's face when using a mobile phone
Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs) to continue the conversation.
See y'all next month!

@ -1627,6 +1627,28 @@ If `this` is falsy, no component is rendered.
<svelte:component this={currentSelection.component} foo={bar}/>
```
### `<svelte:element>`
```sv
<svelte:element this={expression}/>
```
---
The `<svelte:element>` element lets you render an element of a dynamically specified type. This is useful for example when rich text content from a CMS. If the tag is changed, the children will be preserved unless there's a transition attached to the element. Any properties and event listeners present will be applied to the element.
The only supported binding is `bind:this`, since the element type specific bindings that Svelte does at build time (e.g. `bind:value` for input elements) does not work with a dynamic tag type.
If `this` has a nullish value, a warning will be logged in development mode.
```sv
<script>
let tag = 'div';
export let handler;
</script>
<svelte:element this={tag} on:click={handler}>Foo</svelte:element>
```
### `<svelte:window>`
@ -1683,7 +1705,7 @@ All except `scrollX` and `scrollY` are readonly.
Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave`, which don't fire on `window`. It also lets you use [actions](/docs#template-syntax-element-directives-use-action) on the `<body>` element.
`<svelte:body>` also has to appear at the top level of your component.
As with `<svelte:window>`, this element may only appear the top level of your component and must never be inside a block or element.
```sv
<svelte:body
@ -1704,7 +1726,7 @@ Similarly to `<svelte:window>`, this element allows you to add listeners to even
This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `html` content.
As with `<svelte:window>` and `<svelte:body>`, this element has to appear at the top level of your component and cannot be inside a block or other element.
As with `<svelte:window>` and `<svelte:body>`, this element may only appear at the top level of your component and must never be inside a block or element.
```sv
<svelte:head>

@ -148,7 +148,7 @@ setContext(key: any, context: any)
---
Associates an arbitrary `context` object with the current component and the specified `key`. The context is then available to children of the component (including slotted content) with `getContext`.
Associates an arbitrary `context` object with the current component and the specified `key` and returns that object. The context is then available to children of the component (including slotted content) with `getContext`.
Like lifecycle functions, this must be called during component initialisation.

@ -2,11 +2,7 @@
title: Compile time
---
Typically, you won't interact with the Svelte compiler directly, but will instead integrate it into your build system using a bundler plugin:
* [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte) for users of [Rollup](https://rollupjs.org)
* [svelte-loader](https://github.com/sveltejs/svelte-loader) for users of [webpack](https://webpack.js.org)
* or one of the [community-maintained plugins](https://sveltesociety.dev/tools)
Typically, you won't interact with the Svelte compiler directly, but will instead integrate it into your build system using a bundler plugin. The bundler plugin that the Svelte team most recommends and invests in is [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). The [SvelteKit](https://kit.svelte.dev/) framework provides a setup leveraging `vite-plugin-svelte` to build applications as well as a [tool for packaging Svelte component libraries](https://kit.svelte.dev/docs/packaging). Svelte Society maintains a list of [other bundler plugins](https://sveltesociety.dev/tools/#bundling) for additional tools like Rollup and Webpack.
Nonetheless, it's useful to understand how to use the compiler, since bundler plugins generally expose compiler options to you.
@ -77,7 +73,7 @@ The following options can be passed to the compiler. None are required:
| `accessors` | `false` | If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`.
| `customElement` | `false` | If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component.
| `tag` | `null` | A `string` that tells Svelte what tag name to register the custom element with. It must be a lowercase alphanumeric string with at least one hyphen, e.g. `"my-element"`.
| `css` | `true` | If `true`, styles will be included in the JavaScript class and injected at runtime. It's recommended that you set this to `false` and use the CSS that is statically generated, as it will result in smaller JavaScript bundles and better performance.
| `css` | `true` | If `true`, styles will be included in the JavaScript class and injected at runtime for the components actually rendered. If `false`, the CSS will be returned in the `css` field of the compilation result. Most Svelte bundler plugins will set this to `false` and use the CSS that is statically generated for better performance, as it will result in smaller JavaScript bundles and the output can be served as cacheable `.css` files.
| `cssHash` | See right | A function that takes a `{ hash, css, name, filename }` argument and returns the string that is used as a classname for scoped CSS. It defaults to returning `svelte-${hash(css)}`
| `loopGuardTimeout` | 0 | A `number` that tells Svelte to break the loop if it blocks the thread for more than `loopGuardTimeout` ms. This is useful to prevent infinite loops. **Only available when `dev: true`**
| `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out.

@ -20,6 +20,9 @@
height: var(--height);
left: calc(50% - var(--width) / 2);
top: calc(50% - var(--height) / 2);
display: flex;
align-items: center;
padding: 8px;
border-radius: 4px;
background-color: #ff3e00;
color: #fff;

@ -0,0 +1,12 @@
<script>
const options = ['h1', 'h3', 'p'];
let selected = options[0];
</script>
<select bind:value={selected}>
{#each options as option}
<option value={option}>{option}</option>
{/each}
</select>
<svelte:element this={selected}>I'm a {selected} tag</svelte:element>

@ -2,6 +2,6 @@
question: I'm new to Svelte. Where should I start?
---
We think the best way to get started is playing through the interactive [Tutorial](/tutorial). Each step there is mainly focused on one specific aspect and is easy to follow. You'll be editing and running real Svelte components right in your browser.
We think the best way to get started is playing through the interactive [tutorial](/tutorial). Each step there is mainly focused on one specific aspect and is easy to follow. You'll be editing and running real Svelte components right in your browser.
Five to ten minutes should be enough to get you up and running. An hour and a half should get you through the entire tutorial.

@ -4,7 +4,7 @@ question: How do I document my components?
In editors which use the Svelte Language Server you can document Components, functions and exports using specially formatted comments.
````svelte
````sv
<script>
/** What should we call the user? */
export let name = 'world';

@ -6,14 +6,14 @@ You need to install a preprocessor such as [svelte-preprocess](https://github.co
To declare the type of a reactive variable in a Svelte template, you should use the following syntax:
```
```ts
let x: number;
$: x = count + 1;
```
To import a type or interface make sure to use [TypeScript's `type` modifier](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export):
```
```ts
import type { SomeInterface } from './SomeFile';
```

@ -8,4 +8,5 @@ There are a few approaches that people take when testing, but it generally invol
Some resources for getting started with unit testing:
- [Svelte Testing Library](https://testing-library.com/docs/svelte-testing-library/example/)
- [Example using vitest](https://github.com/vitest-dev/vitest/tree/main/examples/svelte)
- [Example using uvu test runner with JSDOM](https://github.com/lukeed/uvu/tree/master/examples/svelte)

@ -4,7 +4,7 @@ title: Keyed each blocks
By default, when you modify the value of an `each` block, it will add and remove items at the *end* of the block, and update any values that have changed. That might not be what you want.
It's easier to show why than to explain. Click the 'Remove first thing' button a few times, and notice what happens: It removes the first `<Thing>` component, but the *last* DOM node. Then it updates the `name` value in the remaining DOM nodes, but not the emoji.
It's easier to show why than to explain. Click the 'Remove first thing' button a few times, and notice what happens: it does not remove the first `<Thing>` component, but rather the *last* DOM node. Then it updates the `name` value in the remaining DOM nodes, but not the emoji.
Instead, we'd like to remove only the first `<Thing>` component and its DOM node, and leave the others unaffected.

@ -10,4 +10,4 @@ We can also use `bind:value` with `<select>` elements. Update line 20:
Note that the `<option>` values are objects rather than strings. Svelte doesn't mind.
> Because we haven't set an initial value of `selected`, the binding will set it to the default value (the first in the list) automatically. Be careful though — until the binding is initialised, `selected` remains undefined, so we can't blindly reference e.g. `selected.id` in the template.
> Because we haven't set an initial value of `selected`, the binding will set it to the default value (the first in the list) automatically. Be careful though — until the binding is initialised, `selected` remains undefined, so we can't blindly reference e.g. `selected.id` in the template. If your use case allows it, you could also set an initial value to bypass this problem.

@ -6,15 +6,17 @@ You can even bind to properties inside an `each` block.
```html
{#each todos as todo}
<input
type=checkbox
bind:checked={todo.done}
>
<div class:done={todo.done}>
<input
type=checkbox
bind:checked={todo.done}
>
<input
placeholder="What needs to be done?"
bind:value={todo.text}
>
<input
placeholder="What needs to be done?"
bind:value={todo.text}
>
</div>
{/each}
```

@ -20,6 +20,9 @@
height: var(--height);
left: calc(50% - var(--width) / 2);
top: calc(50% - var(--height) / 2);
display: flex;
align-items: center;
padding: 8px;
border-radius: 4px;
background-color: #ff3e00;
color: #fff;

@ -20,6 +20,9 @@
height: var(--height);
left: calc(50% - var(--width) / 2);
top: calc(50% - var(--height) / 2);
display: flex;
align-items: center;
padding: 8px;
border-radius: 4px;
background-color: #ff3e00;
color: #fff;

@ -0,0 +1,18 @@
<script>
const options = ['h1', 'h3', 'p'];
let selected = options[0];
</script>
<select bind:value={selected}>
{#each options as option}
<option value={option}>{option}</option>
{/each}
</select>
{#if selected === 'h1'}
<h1>I'm a h1 tag</h1>
{:else if selected === 'h3'}
<h3>I'm a h3 tag</h3>
{:else if selected === 'p'}
<p>I'm a p tag</p>
{/if}

@ -0,0 +1,12 @@
<script>
const options = ['h1', 'h3', 'p'];
let selected = options[0];
</script>
<select bind:value={selected}>
{#each options as option}
<option value={option}>{option}</option>
{/each}
</select>
<svelte:element this={selected}>I'm a {selected} tag</svelte:element>

@ -0,0 +1,23 @@
---
title: <svelte:element>
---
Sometimes we don't know in advance what kind of DOM element to render. `<svelte:element>` comes in handy here. Instead of a sequence of `if` blocks...
```html
{#if selected === 'h1'}
<h1>I'm a h1 tag</h1>
{:else if selected === 'h3'}
<h3>I'm a h3 tag</h3>
{:else if selected === 'p'}
<p>I'm a p tag</p>
{/if}
```
...we can have a single dynamic component:
```html
<svelte:element this={selected}>I'm a {selected} tag</svelte:element>
```
The `this` value can be any string, or a falsy value — if it's falsy, no element is rendered.

@ -16,7 +16,7 @@ Anything exported from a `context="module"` script block becomes an export from
</script>
```
...we can then import it from `App.svelte`...
...we can then import it in `App.svelte`...
```html
<script>
@ -32,4 +32,4 @@ Anything exported from a `context="module"` script block becomes an export from
</button>
```
> You can't have a default export, because the component *is* the default export.
> You can't have a default export, because the component *is* the default export.

@ -519,7 +519,7 @@ export default class Component {
return result;
}
private _extract_exports(node: ExportDefaultDeclaration | ExportNamedDeclaration | ExportAllDeclaration, module_script) {
private _extract_exports(node: ExportDefaultDeclaration | ExportNamedDeclaration | ExportAllDeclaration, module_script: boolean) {
if (node.type === 'ExportDefaultDeclaration') {
return this.error(node as any, compiler_errors.default_export);
}
@ -539,7 +539,7 @@ export default class Component {
extract_names(declarator.id).forEach(name => {
const variable = this.var_lookup.get(name);
variable.export_name = name;
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
if (!module_script && variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(declarator as any, compiler_warnings.unused_export_let(this.name.name, name));
}
});
@ -559,7 +559,7 @@ export default class Component {
if (variable) {
variable.export_name = specifier.exported.name;
if (variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
if (!module_script && variable.writable && !(variable.referenced || variable.referenced_from_script || variable.subscribable)) {
this.warn(specifier as any, compiler_warnings.unused_export_let(this.name.name, specifier.exported.name));
}
}

@ -246,6 +246,10 @@ export default {
code: 'invalid-animation',
message: 'An element that uses the animate directive must be the sole child of a keyed each block'
},
invalid_animation_dynamic_element: {
code: 'invalid-animation',
message: '<svelte:element> cannot have a animate directive'
},
invalid_directive_value: {
code: 'invalid-directive-value',
message: 'Can only bind to an identifier (e.g. `foo`) or a member expression (e.g. `foo.bar` or `foo[baz]`)'

@ -145,6 +145,10 @@ class Declaration {
? this.node.value.children[0]
: this.node.value;
// Don't minify whitespace in custom properties, since some browsers (Chromium < 99)
// treat --foo: ; and --foo:; differently
if (first.type === 'Raw' && /^\s+$/.test(first.value)) return;
let start = first.start;
while (/\s/.test(code.original[start])) start += 1;

@ -63,7 +63,7 @@ export default class EachBlock extends AbstractBlock {
([this.const_tags, this.children] = get_const_tags(info.children, component, this, this));
if (this.has_animation) {
this.children = this.children.filter(child => !isEmptyNode(child));
this.children = this.children.filter(child => !isEmptyNode(child) && !isCommentNode(child));
if (this.children.length !== 1) {
const child = this.children.find(child => !!(child as Element).animation);
@ -83,3 +83,6 @@ export default class EachBlock extends AbstractBlock {
function isEmptyNode(node: INode) {
return node.type === 'Text' && node.data.trim() === '';
}
function isCommentNode(node: INode) {
return node.type === 'Comment';
}

@ -18,12 +18,15 @@ import Let from './Let';
import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces';
import Component from '../Component';
import Expression from './shared/Expression';
import { string_literal } from '../utils/stringify';
import { Literal } from 'estree';
import compiler_warnings from '../compiler_warnings';
import compiler_errors from '../compiler_errors';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const aria_attribute_set = new Set(aria_attributes);
const aria_roles = 'alert alertdialog application article banner blockquote button caption cell checkbox code columnheader combobox complementary contentinfo definition deletion dialog directory document emphasis feed figure form generic graphics-document graphics-object graphics-symbol grid gridcell group heading img link list listbox listitem log main marquee math meter menu menubar menuitem menuitemcheckbox menuitemradio navigation none note option paragraph presentation progressbar radio radiogroup region row rowgroup rowheader scrollbar search searchbox separator slider spinbutton status strong subscript superscript switch tab table tablist tabpanel term textbox time timer toolbar tooltip tree treegrid treeitem'.split(' ');
@ -190,11 +193,26 @@ export default class Element extends Node {
children: INode[];
namespace: string;
needs_manual_style_scoping: boolean;
tag_expr: Expression;
get is_dynamic_element() {
return this.name === 'svelte:element';
}
constructor(component: Component, parent: Node, scope: TemplateScope, info: any) {
super(component, parent, scope, info);
this.name = info.name;
if (info.name === 'svelte:element') {
if (typeof info.tag !== 'string') {
this.tag_expr = new Expression(component, this, scope, info.tag);
} else {
this.tag_expr = new Expression(component, this, scope, string_literal(info.tag) as Literal);
}
} else {
this.tag_expr = new Expression(component, this, scope, string_literal(this.name) as Literal);
}
this.namespace = get_namespace(parent as Element, this, component.namespace);
if (this.namespace !== namespaces.foreign) {

@ -27,10 +27,7 @@ export default class SlotTemplate extends Node {
this.validate_slot_template_placement();
const has_let = info.attributes.some((node) => node.type === 'Let');
if (has_let) {
scope = scope.child();
}
scope = scope.child();
info.attributes.forEach((node) => {
switch (node.type) {

@ -254,11 +254,17 @@ export default class Expression {
const declaration = b`const ${id} = ${node}`;
if (owner.type === 'ConstTag') {
let child_scope = scope;
walk(node, {
enter(node: Node) {
if (node.type === 'Identifier') {
enter(node: Node, parent: any) {
if (map.has(node)) child_scope = map.get(node);
if (node.type === 'Identifier' && is_reference(node, parent)) {
if (child_scope.has(node.name)) return;
this.replace(block.renderer.reference(node, ctx));
}
},
leave(node: Node) {
if (map.has(node)) child_scope = child_scope.parent;
}
});
} else if (dependencies.size === 0 && contextual_dependencies.size === 0) {

@ -48,6 +48,7 @@ export default class Block {
hydrate: Array<Node | Node[]>;
mount: Array<Node | Node[]>;
measure: Array<Node | Node[]>;
restore_measurements: Array<Node | Node[]>;
fix: Array<Node | Node[]>;
animate: Array<Node | Node[]>;
intro: Array<Node | Node[]>;
@ -96,6 +97,7 @@ export default class Block {
hydrate: [],
mount: [],
measure: [],
restore_measurements: [],
fix: [],
animate: [],
intro: [],
@ -326,6 +328,12 @@ export default class Block {
${this.chunks.measure}
}`;
if (this.chunks.restore_measurements.length) {
properties.restore_measurements = x`function #restore_measurements(#measurement) {
${this.chunks.restore_measurements}
}`;
}
properties.fix = x`function #fix() {
${this.chunks.fix}
}`;
@ -379,6 +387,7 @@ export default class Block {
m: ${properties.mount},
p: ${properties.update},
r: ${properties.measure},
s: ${properties.restore_measurements},
f: ${properties.fix},
a: ${properties.animate},
i: ${properties.intro},

@ -26,6 +26,7 @@ import Action from '../../../nodes/Action';
import MustacheTagWrapper from '../MustacheTag';
import RawMustacheTagWrapper from '../RawMustacheTag';
import is_dynamic from '../shared/is_dynamic';
import create_debugging_comment from '../shared/create_debugging_comment';
import { push_array } from '../../../../utils/push_array';
interface BindingGroup {
@ -134,6 +135,8 @@ const events = [
}
];
const CHILD_DYNAMIC_ELEMENT_BLOCK = 'child_dynamic_element';
export default class ElementWrapper extends Wrapper {
node: Element;
fragment: FragmentWrapper;
@ -147,6 +150,9 @@ export default class ElementWrapper extends Wrapper {
var: any;
void: boolean;
child_dynamic_element_block?: Block = null;
child_dynamic_element?: ElementWrapper = null;
constructor(
renderer: Renderer,
block: Block,
@ -156,6 +162,24 @@ export default class ElementWrapper extends Wrapper {
next_sibling: Wrapper
) {
super(renderer, block, parent, node);
if (node.is_dynamic_element && block.type !== CHILD_DYNAMIC_ELEMENT_BLOCK) {
this.child_dynamic_element_block = block.child({
comment: create_debugging_comment(node, renderer.component),
name: renderer.component.get_unique_name('create_dynamic_element'),
type: CHILD_DYNAMIC_ELEMENT_BLOCK
});
renderer.blocks.push(this.child_dynamic_element_block);
this.child_dynamic_element = new ElementWrapper(
renderer,
this.child_dynamic_element_block,
parent,
node,
strip_whitespace,
next_sibling
);
}
this.var = {
type: 'Identifier',
name: node.name.replace(/[^a-zA-Z0-9_$]/g, '_')
@ -199,6 +223,8 @@ export default class ElementWrapper extends Wrapper {
block.add_animation();
}
block.add_dependencies(node.tag_expr.dependencies);
// add directive and handler dependencies
[node.animation, node.outro, ...node.actions, ...node.classes, ...node.styles].forEach(directive => {
if (directive && directive.expression) {
@ -219,7 +245,9 @@ export default class ElementWrapper extends Wrapper {
node.classes.length > 0 ||
node.intro || node.outro ||
node.handlers.length > 0 ||
node.styles.length > 0 ||
this.node.name === 'option' ||
node.tag_expr.dynamic_dependencies().length ||
renderer.options.dev
) {
this.parent.cannot_use_innerhtml(); // need to use add_location
@ -231,6 +259,110 @@ export default class ElementWrapper extends Wrapper {
}
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
if (this.child_dynamic_element) {
this.render_dynamic_element(block, parent_node, parent_nodes);
} else {
this.render_element(block, parent_node, parent_nodes);
}
}
render_dynamic_element(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
this.child_dynamic_element.render(
this.child_dynamic_element_block,
null,
(x`#nodes` as unknown) as Identifier
);
const previous_tag = block.get_unique_name('previous_tag');
const tag = this.node.tag_expr.manipulate(block);
block.add_variable(previous_tag, tag);
block.chunks.init.push(b`
${this.renderer.options.dev && b`@validate_dynamic_element(${tag});`}
let ${this.var} = ${tag} && ${this.child_dynamic_element_block.name}(#ctx);
`);
block.chunks.create.push(b`
if (${this.var}) ${this.var}.c();
`);
if (this.renderer.options.hydratable) {
block.chunks.claim.push(b`
if (${this.var}) ${this.var}.l(${parent_nodes});
`);
}
block.chunks.mount.push(b`
if (${this.var}) ${this.var}.m(${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});
`);
const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
const has_transitions = !!(this.node.intro || this.node.outro);
const not_equal = this.renderer.component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`;
block.chunks.update.push(b`
if (${tag}) {
if (!${previous_tag}) {
${this.var} = ${this.child_dynamic_element_block.name}(#ctx);
${this.var}.c();
${has_transitions && b`@transition_in(${this.var})`}
${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});
} else if (${not_equal}(${previous_tag}, ${tag})) {
${this.var}.d(1);
${this.renderer.options.dev && b`@validate_dynamic_element(${tag});`}
${this.var} = ${this.child_dynamic_element_block.name}(#ctx);
${this.var}.c();
${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});
} else {
${this.var}.p(#ctx, #dirty);
}
} else if (${previous_tag}) {
${
has_transitions
? b`
@group_outros();
@transition_out(${this.var}, 1, 1, () => {
${this.var} = null;
});
@check_outros();
`
: b`
${this.var}.d(1);
${this.var} = null;
`
}
}
${previous_tag} = ${tag};
`);
if (this.child_dynamic_element_block.has_intros) {
block.chunks.intro.push(b`@transition_in(${this.var});`);
}
if (this.child_dynamic_element_block.has_outros) {
block.chunks.outro.push(b`@transition_out(${this.var});`);
}
block.chunks.destroy.push(b`if (${this.var}) ${this.var}.d(detaching)`);
if (this.node.animation) {
const measurements = block.get_unique_name('measurements');
block.add_variable(measurements);
block.chunks.measure.push(b`${measurements} = ${this.var}.r()`);
block.chunks.fix.push(b`${this.var}.f();`);
block.chunks.animate.push(b`
${this.var}.s(${measurements});
${this.var}.a()
`);
}
}
is_dom_node() {
return super.is_dom_node() && !this.child_dynamic_element;
}
render_element(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
const { renderer } = this;
if (this.node.name === 'noscript') return;
@ -248,7 +380,7 @@ export default class ElementWrapper extends Wrapper {
if (renderer.options.hydratable) {
if (parent_nodes) {
block.chunks.claim.push(b`
${node} = ${this.get_claim_statement(parent_nodes)};
${node} = ${this.get_claim_statement(block, parent_nodes)};
`);
if (!this.void && this.node.children.length > 0) {
@ -356,6 +488,8 @@ export default class ElementWrapper extends Wrapper {
b`@add_location(${this.var}, ${renderer.file_var}, ${loc.line - 1}, ${loc.column}, ${this.node.start});`
);
}
block.renderer.dirty(this.node.tag_expr.dynamic_dependencies());
}
can_use_textcontent() {
@ -363,7 +497,7 @@ export default class ElementWrapper extends Wrapper {
}
get_render_statement(block: Block) {
const { name, namespace } = this.node;
const { name, namespace, tag_expr } = this.node;
if (namespace === namespaces.svg) {
return x`@svg_element("${name}")`;
@ -378,22 +512,32 @@ export default class ElementWrapper extends Wrapper {
return x`@element_is("${name}", ${is.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`)})`;
}
return x`@element("${name}")`;
const reference = tag_expr.manipulate(block);
return x`@element(${reference})`;
}
get_claim_statement(nodes: Identifier) {
get_claim_statement(block: Block, nodes: Identifier) {
const attributes = this.attributes
.filter((attr) => !(attr instanceof SpreadAttributeWrapper) && !attr.property_name)
.map((attr) => p`${(attr as StyleAttributeWrapper | AttributeWrapper).name}: true`);
const name = this.node.namespace
? this.node.name
: this.node.name.toUpperCase();
let reference;
if (this.node.tag_expr.node.type === 'Literal') {
if (this.node.namespace) {
reference = `"${this.node.tag_expr.node.value}"`;
} else {
reference = `"${(this.node.tag_expr.node.value as String || '').toUpperCase()}"`;
}
} else if (this.node.namespace) {
reference = x`${this.node.tag_expr.manipulate(block)}`;
} else {
reference = x`(${this.node.tag_expr.manipulate(block)} || 'null').toUpperCase()`;
}
if (this.node.namespace === namespaces.svg) {
return x`@claim_svg_element(${nodes}, "${name}", { ${attributes} })`;
return x`@claim_svg_element(${nodes}, ${reference}, { ${attributes} })`;
} else {
return x`@claim_element(${nodes}, "${name}", { ${attributes} })`;
return x`@claim_element(${nodes}, ${reference}, { ${attributes} })`;
}
}
@ -846,6 +990,11 @@ export default class ElementWrapper extends Wrapper {
${rect} = ${this.var}.getBoundingClientRect();
`);
if (block.type === CHILD_DYNAMIC_ELEMENT_BLOCK) {
block.chunks.measure.push(b`return ${rect}`);
block.chunks.restore_measurements.push(b`${rect} = #measurement;`);
}
block.chunks.fix.push(b`
@fix_position(${this.var});
${stop_animation}();
@ -939,7 +1088,7 @@ export default class ElementWrapper extends Wrapper {
if (should_cache) {
block.chunks.update.push(b`
if (${block.renderer.dirty(dependencies)} && (${cached_snippet} !== (${cached_snippet} = ${snippet}))) {
${updater}
${updater}
}
`);
} else {

@ -36,6 +36,7 @@ export default class KeyBlockWrapper extends Wrapper {
name: renderer.component.get_unique_name('create_key_block'),
type: 'key'
});
block.add_dependencies(node.expression.dependencies);
renderer.blocks.push(block);
}

@ -8,8 +8,9 @@ import Expression from '../../nodes/shared/Expression';
import remove_whitespace_children from './utils/remove_whitespace_children';
import fix_attribute_casing from '../../render_dom/wrappers/Element/fix_attribute_casing';
import { namespaces } from '../../../utils/namespaces';
import { Expression as ESExpression } from 'estree';
export default function(node: Element, renderer: Renderer, options: RenderOptions) {
export default function (node: Element, renderer: Renderer, options: RenderOptions) {
const children = remove_whitespace_children(node.children, node.next);
@ -22,7 +23,8 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
node.attributes.some((attribute) => attribute.name === 'contenteditable')
);
renderer.add_string(`<${node.name}`);
renderer.add_string('<');
add_tag_name();
const class_expression_list = node.classes.map(class_directive => {
const { expression, name } = class_directive;
@ -167,14 +169,25 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
renderer.add_expression(node_contents);
}
if (!is_void(node.name)) {
renderer.add_string(`</${node.name}>`);
}
add_close_tag();
} else {
renderer.render(children, options);
add_close_tag();
}
function add_close_tag() {
if (!is_void(node.name)) {
renderer.add_string(`</${node.name}>`);
renderer.add_string('</');
add_tag_name();
renderer.add_string('>');
}
}
function add_tag_name() {
if (node.tag_expr.node.type === 'Literal') {
renderer.add_string(node.tag_expr.node.value as string);
} else {
renderer.add_expression(node.tag_expr.node as ESExpression);
}
}
}

@ -99,6 +99,10 @@ export default {
code: `invalid-${slug}-content`,
message: `<${name}> cannot have children`
}),
invalid_element_definition: {
code: 'invalid-element-definition',
message: 'Invalid element definition'
},
invalid_element_placement: (slug: string, name: string) => ({
code: `invalid-${slug}-placement`,
message: `<${name}> tags cannot be inside elements or blocks`
@ -161,6 +165,10 @@ export default {
code: 'missing-attribute-value',
message: 'Expected value for the attribute'
},
missing_element_definition: {
code: 'missing-element-definition',
message: '<svelte:element> must have a \'this\' attribute'
},
unclosed_script: {
code: 'unclosed-script',
message: '<script> must have a closing tag'

@ -19,7 +19,7 @@ const meta_tags = new Map([
['svelte:body', 'Body']
]);
const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:fragment');
const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:fragment', 'svelte:element');
const specials = new Map([
[
@ -41,6 +41,7 @@ const specials = new Map([
const SELF = /^svelte:self(?=[\s/>])/;
const COMPONENT = /^svelte:component(?=[\s/>])/;
const SLOT = /^svelte:fragment(?=[\s/>])/;
const ELEMENT = /^svelte:element(?=[\s/>])/;
function parent_is_head(stack) {
let i = stack.length;
@ -84,7 +85,7 @@ export default function tag(parser: Parser) {
parser.current().children.length
) {
parser.error(
parser_errors.invalid_element_content(slug, name),
parser_errors.invalid_element_content(slug, name),
parser.current().children[0].start
);
}
@ -169,7 +170,7 @@ export default function tag(parser: Parser) {
if (name === 'svelte:component') {
const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this');
if (!~index) {
if (index === -1) {
parser.error(parser_errors.missing_component_definition, start);
}
@ -181,6 +182,19 @@ export default function tag(parser: Parser) {
element.expression = definition.value[0].expression;
}
if (name === 'svelte:element') {
const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this');
if (index === -1) {
parser.error(parser_errors.missing_element_definition, start);
}
const definition = element.attributes.splice(index, 1)[0];
if (definition.value === true) {
parser.error(parser_errors.invalid_element_definition, definition.start);
}
element.tag = definition.value[0].data || definition.value[0].expression;
}
// special cases top-level <script> and <style>
if (specials.has(name) && parser.stack.length === 1) {
const special = specials.get(name);
@ -247,6 +261,7 @@ function read_tag_name(parser: Parser) {
}
if (parser.read(COMPONENT)) return 'svelte:component';
if (parser.read(ELEMENT)) return 'svelte:element';
if (parser.read(SLOT)) return 'svelte:fragment';
@ -258,7 +273,7 @@ function read_tag_name(parser: Parser) {
const match = fuzzymatch(name.slice(7), valid_meta_tags);
parser.error(
parser_errors.invalid_tag_name_svelte_element(valid_meta_tags, match),
parser_errors.invalid_tag_name_svelte_element(valid_meta_tags, match),
start
);
}

@ -56,6 +56,7 @@ export const globals = new Set([
'setTimeout',
'String',
'SVGElement',
'Symbol',
'SyntaxError',
'TypeError',
'undefined',

@ -0,0 +1,42 @@
/**
* Actions can return an object containing the two properties defined in this interface. Both are optional.
* - update: An action can have a parameter. This method will be called whenever that parameter changes,
* immediately after Svelte has applied updates to the markup.
* - destroy: Method that is called after the element is unmounted
*
* Example usage:
* ```ts
* export function myAction(node: HTMLElement, parameter: Parameter): ActionReturn<Parameter> {
* // ...
* return {
* update: (updatedParameter) => {...},
* destroy: () => {...}
* };
* }
* ```
*
* Docs: https://svelte.dev/docs#template-syntax-element-directives-use-action
*/
export interface ActionReturn<Parameter = any> {
update?: (parameter: Parameter) => void;
destroy?: () => void;
}
/**
* Actions are functions that are called when an element is created.
* You can use this interface to type such actions.
* The following example defines an action that only works on `<div>` elements
* and optionally accepts a parameter which it has a default value for:
* ```ts
* export const myAction: Action<HTMLDivElement, { someProperty: boolean }> = (node, param = { someProperty: true }) => {
* // ...
* }
* ```
* You can return an object with methods `update` and `destroy` from the function.
* See interface `ActionReturn` for more details.
*
* Docs: https://svelte.dev/docs#template-syntax-element-directives-use-action
*/
export interface Action<Element = HTMLElement, Parameter = any> {
<Node extends Element>(node: Node, parameter?: Parameter): void | ActionReturn<Parameter>;
}

@ -107,6 +107,12 @@ export function validate_slots(name, slot, keys) {
}
}
export function validate_dynamic_element(tag: unknown) {
if (tag && typeof tag !== 'string') {
throw new Error('<svelte:element> expects "this" attribute to be a string.');
}
}
type Props = Record<string, any>;
export interface SvelteComponentDev {
$set(props?: Props): void;

@ -57,8 +57,9 @@ export function createEventDispatcher<EventMap extends {} = any>(): <
};
}
export function setContext<T>(key, context: T) {
export function setContext<T>(key, context: T): T {
get_current_component().$$.context.set(key, context);
return context;
}
export function getContext<T>(key): T {

@ -177,7 +177,8 @@ export function create_ssr_component(fn) {
export function add_attribute(name, value, boolean) {
if (value == null || (boolean && !value)) return '';
return ` ${name}${value === true && boolean_attributes.has(name) ? '' : `=${typeof value === 'string' ? JSON.stringify(escape(value)) : `"${value}"`}`}`;
const assignment = (boolean && value === true) ? '' : `="${escape_attribute_value(value.toString())}"`;
return ` ${name}${assignment}`;
}
export function add_classes(classes) {

@ -1 +1 @@
:root{--root-test:20}div.svelte-xyz{--test:10}
:root{--root-test:20}div.svelte-xyz{--test:10}div.svelte-xyz{--foo: ;--bar: !important}

@ -7,4 +7,9 @@
div {
--test: 10;
}
div {
--foo: ;
--bar: !important;
}
</style>

@ -0,0 +1,21 @@
export default {
warnings: [
{
code: 'css-unused-selector',
end: {
character: 86,
column: 8,
line: 7
},
frame:
' 5: color: red;\n 6: }\n 7: .unused {\n ^\n 8: font-style: italic;\n 9: }',
message: 'Unused CSS selector ".unused"',
pos: 79,
start: {
character: 79,
column: 1,
line: 7
}
}
]
};

@ -0,0 +1 @@
.used.svelte-xyz{color:red}

@ -0,0 +1 @@
<div class="used svelte-xyz"></div>

@ -0,0 +1,10 @@
<svelte:element this="div" class="used" />
<style>
.used {
color: red;
}
.unused {
font-style: italic;
}
</style>

@ -15,4 +15,4 @@ const Component = create_ssr_component(($$result, $$props, $$bindings, slots) =>
<p>foo: ${escape(foo)}</p>`;
});
export default Component;
export default Component;

@ -0,0 +1,2 @@
<svelte:element this="div"></svelte:element>
<svelte:element this="div" class="foo"></svelte:element>

@ -0,0 +1,50 @@
{
"html": {
"start": 0,
"end": 101,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 44,
"type": "Element",
"name": "svelte:element",
"attributes": [],
"children": [],
"tag": "div"
},
{
"type": "Text",
"start": 44,
"end": 45,
"data": "\n",
"raw": "\n"
},
{
"start": 45,
"end": 101,
"type": "Element",
"name": "svelte:element",
"attributes": [
{
"type": "Attribute",
"start": 72,
"end": 83,
"name": "class",
"value": [
{
"type": "Text",
"start": 79,
"end": 82,
"data": "foo",
"raw": "foo"
}
]
}
],
"children": [],
"tag": "div"
}
]
}
}

@ -0,0 +1,2 @@
<svelte:element this={tag}></svelte:element>
<svelte:element this={tag} class="foo"></svelte:element>

@ -0,0 +1,80 @@
{
"html": {
"start": 0,
"end": 101,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 44,
"type": "Element",
"name": "svelte:element",
"attributes": [],
"children": [],
"tag": {
"start": 22,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 22
},
"end": {
"line": 1,
"column": 25
}
},
"name": "tag",
"type": "Identifier"
}
},
{
"type": "Text",
"start": 44,
"end": 45,
"data": "\n",
"raw": "\n"
},
{
"start": 45,
"end": 101,
"type": "Element",
"name": "svelte:element",
"children": [],
"attributes": [
{
"type": "Attribute",
"start": 72,
"end": 83,
"name": "class",
"value": [
{
"type": "Text",
"start": 79,
"end": 82,
"data": "foo",
"raw": "foo"
}
]
}
],
"tag": {
"start": 67,
"end": 70,
"loc": {
"start": {
"line": 2,
"column": 22
},
"end": {
"line": 2,
"column": 25
}
},
"name": "tag",
"type": "Identifier"
}
}
]
}
}

@ -1,6 +1,6 @@
{
"code": "invalid-tag-name",
"message": "Valid <svelte:...> tag names are svelte:head, svelte:options, svelte:window, svelte:body, svelte:self, svelte:component or svelte:fragment",
"message": "Valid <svelte:...> tag names are svelte:head, svelte:options, svelte:window, svelte:body, svelte:self, svelte:component, svelte:fragment or svelte:element",
"pos": 10,
"start": {
"character": 10,

@ -0,0 +1,15 @@
export default {
html: `
<div>static dynamic</div>
<div>static dynamic</div>
<div>static dynamic</div>
`,
async test({ component, target, assert }) {
component.props = 'xxx';
assert.htmlEqual(target.innerHTML, `
<div>static xxx</div>
<div>static xxx</div>
<div>static xxx</div>
`);
}
};

@ -0,0 +1,24 @@
<script>
import Component from './Component.svelte';
export let props = "dynamic";
</script>
<Component>
<svelte:fragment slot="box1">
{@const foo = "static"}
{@const bar = props}
<div>{foo} {bar}</div>
</svelte:fragment>
<svelte:fragment>
{@const foo = "static"}
{@const bar = props}
<div>{foo} {bar}</div>
</svelte:fragment>
</Component>
<Component>
{@const foo = "static"}
{@const bar = props}
<div>{foo} {bar}</div>
</Component>

@ -0,0 +1,29 @@
export default {
html: `
<p>0</p>
<p>bar: 1,2,3,1,1,2,3,2, num: 1</p>
<p>bar: 0,2,4,1,0,2,4,2, num: 2</p>
`,
async test({ component, target, assert }) {
assert.htmlEqual(
target.innerHTML,
`
<p>0</p>
<p>bar: 1,2,3,1,1,2,3,2, num: 1</p>
<p>bar: 0,2,4,1,0,2,4,2, num: 2</p>
`
);
component.nums = [1, 2, 3];
assert.htmlEqual(
target.innerHTML,
`
<p>0</p>
<p>bar: 1,2,3,1,1,2,3,2,1,2,3,3, num: 1</p>
<p>bar: 0,2,4,1,0,2,4,2,0,2,4,3, num: 2</p>
<p>bar: -100,0,100,1,-100,0,100,2,-100,0,100,3, num: 3</p>
`
);
}
};

@ -0,0 +1,26 @@
<script>
export let nums = [1, 2];
let foos = [
{
nums: [1, 2, 3],
},
{
nums: [0, 2, 4],
},
{
nums: [-100, 0, 100],
},
];
let foo = 0;
</script>
<p>{foo}</p>
{#each nums as num, index}
{@const bar = nums.map((num) => {
const func = (foos, num) => {
return [...foos.map((foo) => foo), num];
}
return func(foos[index].nums, num);
})}
<p>bar: {bar}, num: {num}</p>
{/each}

@ -0,0 +1,29 @@
export default {
html: `
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 1</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 2</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 3</p>
`,
async test({ component, target, assert }) {
assert.htmlEqual(
target.innerHTML,
`
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 1</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 2</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 3</p>
`
);
component.nums = [1, 2, 3, 4];
assert.htmlEqual(
target.innerHTML,
`
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 1</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 2</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 3</p>
<p>bar: 1,2,3,0,2,4,-100,0,100, num: 4</p>
`
);
}
};

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save