mirror of https://github.com/sveltejs/svelte
fix: allow component to be mounted in iframe (#13225)
* fix: allow component to be mounted in iframe * prettier * prettier * fix: allow HMR cleanup styles in iframe and custom elements * add test * avoid creating unnecessary microtasks * simplify * rename stuff * typo * lint * changeset * changeset --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> Co-authored-by: Rich Harris <rich.harris@vercel.com> Co-authored-by: Rich Harris <hello@rich-harris.dev>pull/13290/head
parent
a680e6f2e7
commit
5210ae2610
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: allow custom element styles to be updated in HMR mode
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: inject styles correctly when mounting inside an iframe
|
@ -0,0 +1,31 @@
|
|||||||
|
/** @type {Map<String, Set<HTMLStyleElement>>} */
|
||||||
|
var all_styles = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} hash
|
||||||
|
* @param {HTMLStyleElement} style
|
||||||
|
*/
|
||||||
|
export function register_style(hash, style) {
|
||||||
|
var styles = all_styles.get(hash);
|
||||||
|
|
||||||
|
if (!styles) {
|
||||||
|
styles = new Set();
|
||||||
|
all_styles.set(hash, styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
styles.add(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} hash
|
||||||
|
*/
|
||||||
|
export function cleanup_styles(hash) {
|
||||||
|
var styles = all_styles.get(hash);
|
||||||
|
if (!styles) return;
|
||||||
|
|
||||||
|
for (const style of styles) {
|
||||||
|
style.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
all_styles.delete(hash);
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<script>
|
||||||
|
import { mount } from 'svelte';
|
||||||
|
import Child from './Child.svelte';
|
||||||
|
|
||||||
|
let { count } = $props();
|
||||||
|
|
||||||
|
let iframe;
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
mount(Child, {
|
||||||
|
target: iframe.contentWindow.document.body,
|
||||||
|
props: {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<iframe title="container" bind:this={iframe}></iframe>
|
@ -0,0 +1,13 @@
|
|||||||
|
<svelte:options css="injected" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let { count } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>count: {count}</h1>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,22 @@
|
|||||||
|
import { flushSync } from 'svelte';
|
||||||
|
import { test } from '../../assert';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
async test({ target, assert }) {
|
||||||
|
const button = target.querySelector('button');
|
||||||
|
const h1 = () =>
|
||||||
|
/** @type {HTMLHeadingElement} */ (
|
||||||
|
/** @type {Window} */ (
|
||||||
|
target.querySelector('iframe')?.contentWindow
|
||||||
|
).document.querySelector('h1')
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(h1().textContent, 'count: 0');
|
||||||
|
assert.equal(getComputedStyle(h1()).color, 'rgb(255, 0, 0)');
|
||||||
|
|
||||||
|
flushSync(() => button?.click());
|
||||||
|
|
||||||
|
assert.equal(h1().textContent, 'count: 1');
|
||||||
|
assert.equal(getComputedStyle(h1()).color, 'rgb(255, 0, 0)');
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import App from './App.svelte';
|
||||||
|
|
||||||
|
let count = $state(0);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => (count += 1)}>remount</button>
|
||||||
|
|
||||||
|
{#key count}
|
||||||
|
<App {count} />
|
||||||
|
{/key}
|
Loading…
Reference in new issue