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