Skip to content
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

transition in custom element #4998

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/runtime/internal/style_manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { element } from './dom';
import { raf } from './environment';
import { is_function } from './utils';

interface ExtendedDoc extends Document {
__svelte_stylesheet: CSSStyleSheet;
Expand All @@ -18,6 +19,21 @@ function hash(str: string) {
return hash >>> 0;
}

function append_style(doc) {
return doc.host ?
doc.insertBefore(element('style') as HTMLStyleElement, doc.firstElementChild) :
doc.head.appendChild(element('style') as HTMLStyleElement);
}

function get_root_node(node) {
if (is_function(node.getRootNode)) return node.getRootNode();
Copy link

@mahdimaiche mahdimaiche Feb 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a weird behaviour doing so, let's suppose we have a transition on hover on an element, if the element on which we want to apply the transition is directly a child of a shadow-root element it will be okay, if otherwise it's a child of a regular DOM node (let's say a div) it will keep on appending style tags on each hover. Looking recursively for a parenElement to get to the root of the webComponent solves the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, thanks. Could you show me your code so I can have a look as well?

let rootNode = node.parentNode;
while (rootNode.parentNode != null) {
rootNode = rootNode.parentNode;
}
return rootNode;
}

export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b: number, duration: number, delay: number, ease: (t: number) => number, fn: (t: number, u: number) => string, uid: number = 0) {
const step = 16.666 / duration;
let keyframes = '{\n';
Expand All @@ -29,9 +45,9 @@ export function create_rule(node: Element & ElementCSSInlineStyle, a: number, b:

const rule = keyframes + `100% {${fn(b, 1 - b)}}\n}`;
const name = `__svelte_${hash(rule)}_${uid}`;
const doc = node.ownerDocument as ExtendedDoc;
const doc = get_root_node(node) as ExtendedDoc;
active_docs.add(doc);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = doc.head.appendChild(element('style') as HTMLStyleElement).sheet as CSSStyleSheet);
const stylesheet = doc.__svelte_stylesheet || (doc.__svelte_stylesheet = append_style(doc).sheet as CSSStyleSheet);
const current_rules = doc.__svelte_rules || (doc.__svelte_rules = {});

if (!current_rules[name]) {
Expand Down
12 changes: 11 additions & 1 deletion test/custom-elements/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ describe('custom-elements', function() {

const solo = /\.solo$/.test(dir);
const skip = /\.skip$/.test(dir);
const easing = path.resolve('easing/index.mjs');
const internal = path.resolve('internal/index.mjs');
const transition = path.resolve('transition/index.mjs');
const index = path.resolve('index.mjs');
const warnings = [];

Expand All @@ -76,10 +78,18 @@ describe('custom-elements', function() {
plugins: [
{
resolveId(importee) {
if (importee === 'svelte/internal' || importee === './internal') {
if (importee === '../easing') {
return easing;
}

if (importee === 'svelte/internal' || importee === './internal' || importee === '../internal') {
return internal;
}

if (importee === 'svelte/transition' || importee === './transition') {
return transition;
}

if (importee === 'svelte') {
return index;
}
Expand Down
18 changes: 18 additions & 0 deletions test/custom-elements/samples/transition/main.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<svelte:options tag="custom-element"/>

<script>
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';

let show = false;

onMount(() => {
show = true;
});
</script>

{#if show}
<p transition:fade>
Fades in and out
</p>
{/if}
18 changes: 18 additions & 0 deletions test/custom-elements/samples/transition/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as assert from 'assert';
import './main.svelte';

export default async function (target) {
target.innerHTML = '<custom-element></custom-element>';

// wait one tick in order for styles to be applied
await Promise.resolve();

const el = target.querySelector('custom-element');
const style = el.shadowRoot.querySelector('style');

assert.ok(style);
assert.ok(style.sheet);
assert.equal(style, el.shadowRoot.firstElementChild);
assert.equal(style.sheet.cssRules.length, 1);
assert.equal(el.shadowRoot.__svelte_stylesheet, style.sheet);
}