diff --git a/documentation/docs/03-template-syntax/12-bind.md b/documentation/docs/03-template-syntax/12-bind.md
index a59a2d8321e8..de57815687dc 100644
--- a/documentation/docs/03-template-syntax/12-bind.md
+++ b/documentation/docs/03-template-syntax/12-bind.md
@@ -4,7 +4,7 @@ title: bind:
Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent.
-The general syntax is `bind:property={expression}`, where `expression` is an _lvalue_ (i.e. a variable or an object property). When the expression is an identifier with the same name as the property, we can omit the expression — in other words these are equivalent:
+The general syntax is `bind:property={expression}`, where `expression` is an [_lvalue_](https://press.rebus.community/programmingfundamentals/chapter/lvalue-and-rvalue/) (i.e. a variable or an object property). When the expression is an identifier with the same name as the property, we can omit the expression — in other words these are equivalent:
```svelte
diff --git a/documentation/docs/07-misc/04-custom-elements.md b/documentation/docs/07-misc/04-custom-elements.md
index a8e0c8176316..7e6a17b947c9 100644
--- a/documentation/docs/07-misc/04-custom-elements.md
+++ b/documentation/docs/07-misc/04-custom-elements.md
@@ -114,6 +114,8 @@ When constructing a custom element, you can tailor several aspects by defining `
...
```
+> [!NOTE] While Typescript is supported in the `extend` function, it is subject to limitations: you need to set `lang="ts"` on one of the scripts AND you can only use [erasable syntax](https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly) in it. They are not processed by script preprocessors.
+
## Caveats and limitations
Custom elements can be a useful way to package components for consumption in a non-Svelte app, as they will work with vanilla HTML and JavaScript as well as [most frameworks](https://custom-elements-everywhere.com/). There are, however, some important differences to be aware of:
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index 62b1db37596c..dae7f68e859f 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,13 @@
# svelte
+## 5.33.3
+
+### Patch Changes
+
+- fix: allow using typescript in `customElement.extend` option ([#16001](https://github.com/sveltejs/svelte/pull/16001))
+
+- fix: cleanup event handlers on media elements ([#16005](https://github.com/sveltejs/svelte/pull/16005))
+
## 5.33.2
### Patch Changes
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 65af4a543f2a..3f625f1590ad 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
- "version": "5.33.2",
+ "version": "5.33.3",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js
index 42427dd9c407..756a88a824b6 100644
--- a/packages/svelte/src/compiler/index.js
+++ b/packages/svelte/src/compiler/index.js
@@ -43,6 +43,11 @@ export function compile(source, options) {
instance: parsed.instance && remove_typescript_nodes(parsed.instance),
module: parsed.module && remove_typescript_nodes(parsed.module)
};
+ if (combined_options.customElementOptions?.extend) {
+ combined_options.customElementOptions.extend = remove_typescript_nodes(
+ combined_options.customElementOptions?.extend
+ );
+ }
}
const analysis = analyze_component(parsed, source, combined_options);
diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js
index c2b7fc7d838d..fa3bf0b0210a 100644
--- a/packages/svelte/src/internal/client/dom/elements/events.js
+++ b/packages/svelte/src/internal/client/dom/elements/events.js
@@ -112,8 +112,15 @@ export function event(event_name, dom, handler, capture, passive) {
var options = { capture, passive };
var target_handler = create_event(event_name, dom, handler, options);
- // @ts-ignore
- if (dom === document.body || dom === window || dom === document) {
+ if (
+ dom === document.body ||
+ // @ts-ignore
+ dom === window ||
+ // @ts-ignore
+ dom === document ||
+ // Firefox has quirky behavior, it can happen that we still get "canplay" events when the element is already removed
+ dom instanceof HTMLMediaElement
+ ) {
teardown(() => {
dom.removeEventListener(event_name, target_handler, options);
});
diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js
index 2184f10a6c92..fb2f3752732c 100644
--- a/packages/svelte/src/version.js
+++ b/packages/svelte/src/version.js
@@ -4,5 +4,5 @@
* The current version, as set in package.json.
* @type {string}
*/
-export const VERSION = '5.33.2';
+export const VERSION = '5.33.3';
export const PUBLIC_VERSION = '5';
diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/extend-with-ts/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/extend-with-ts/_config.js
new file mode 100644
index 000000000000..6502a08290c5
--- /dev/null
+++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/extend-with-ts/_config.js
@@ -0,0 +1,19 @@
+import { test } from '../../assert';
+const tick = () => Promise.resolve();
+
+export default test({
+ async test({ assert, target }) {
+ target.innerHTML = '
name: world
+ ` + ); + assert.equal(el.test, `test`); + } +}); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/extend-with-ts/main.svelte b/packages/svelte/tests/runtime-browser/custom-elements-samples/extend-with-ts/main.svelte new file mode 100644 index 000000000000..ddd2d4b61ac6 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/extend-with-ts/main.svelte @@ -0,0 +1,14 @@ +name: {name}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/event-media-element-cleanup/_config.js b/packages/svelte/tests/runtime-runes/samples/event-media-element-cleanup/_config.js new file mode 100644 index 000000000000..775afcab8913 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-media-element-cleanup/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { expect, vi } from 'vitest'; + +const handler = vi.fn(); + +export default test({ + props: { + handler + }, + async test({ target }) { + const button = target.querySelector('button'); + const video = target.querySelector('video'); + + button?.click(); + flushSync(); + video?.dispatchEvent(new Event('someevent')); + expect(handler).not.toHaveBeenCalled(); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/event-media-element-cleanup/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-media-element-cleanup/main.svelte new file mode 100644 index 000000000000..6a1f9b6b4b8c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-media-element-cleanup/main.svelte @@ -0,0 +1,9 @@ + + + +{#if show} + +{/if}Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: