-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: introduce $host
rune, deprecate createEventDispatcher
#11059
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"svelte": patch | ||
--- | ||
|
||
feat: introduce `$host` rune, deprecate `createEventDispatcher` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { test } from '../../test'; | ||
|
||
export default test({ | ||
error: { | ||
code: 'invalid-host-location', | ||
message: '$host() can only be used inside custom element component instances' | ||
} | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<script> | ||
$host(); | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
$host(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { test } from '../../assert'; | ||
const tick = () => Promise.resolve(); | ||
|
||
export default test({ | ||
async test({ assert, target }) { | ||
target.innerHTML = '<custom-element></custom-element>'; | ||
/** @type {any} */ | ||
const el = target.querySelector('custom-element'); | ||
|
||
/** @type {string[]} */ | ||
const events = []; | ||
const handle_evt = (e) => events.push(e.type, e.detail); | ||
el.addEventListener('greeting', handle_evt); | ||
|
||
await tick(); | ||
|
||
el.shadowRoot.querySelector('button').click(); | ||
assert.deepEqual(events, ['greeting', 'hello']); | ||
|
||
el.removeEventListener('greeting', handle_evt); | ||
el.shadowRoot.querySelector('button').click(); | ||
assert.deepEqual(events, ['greeting', 'hello']); | ||
} | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<svelte:options customElement="custom-element" /> | ||
|
||
<script> | ||
function greet(greeting) { | ||
$host().dispatchEvent(new CustomEvent('greeting', { detail: greeting })) | ||
} | ||
</script> | ||
|
||
<button onclick={() => greet('hello')}>say hello</button> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -561,6 +561,26 @@ $inspect(stuff).with(console.trace); | |
|
||
> `$inspect` only works during development. | ||
|
||
## `$host` | ||
|
||
Retrieves the `this` reference of the custom element that contains this component. Example: | ||
|
||
```svelte | ||
<svelte:options customElement="my-element" /> | ||
|
||
<script> | ||
function greet(greeting) { | ||
$host().dispatchEvent( | ||
new CustomEvent('greeting', { detail: greeting }) | ||
); | ||
} | ||
</script> | ||
|
||
<button onclick={() => greet('hello')}>say hello</button> | ||
``` | ||
|
||
> Only available inside custom element components, and only on the client-side | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This raises an interesting question — what even is a server-side custom element component? What is supposed to get rendered? Should we be emitting declarative shadow DOM? Are there any situations where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling The question what we should be doing on the server is interesting indeed - I'm not even sure what would happen today if you do that. It's a larger/separate conversation IMO There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about a proxy that threw on property access? That way if someone did something like const parent = $host().parentNode; they would get a more useful error than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That could have unintended consequences in the case of checking if host is defined when writing code that is eagerly executed on the server |
||
|
||
## How to opt in | ||
|
||
Current Svelte code will continue to work without any adjustments. Components using the Svelte 4 syntax can use components using runes and vice versa. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
takes a generic because people could add their own properties to the element when using the
extend
feature of thecustomElement
option and then want type-safety using it