mirror of https://github.com/sveltejs/svelte
commit
dd9bb711d2
@ -1,120 +1,49 @@
|
|||||||
|
import { to_class } from '../../../shared/attributes.js';
|
||||||
import { hydrating } from '../hydration.js';
|
import { hydrating } from '../hydration.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {SVGElement} dom
|
* @param {Element} dom
|
||||||
* @param {string} value
|
* @param {boolean | number} is_html
|
||||||
* @param {string} [hash]
|
* @param {string | null} value
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
export function set_svg_class(dom, value, hash) {
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
|
||||||
var prev_class_name = dom.__className;
|
|
||||||
var next_class_name = to_class(value, hash);
|
|
||||||
|
|
||||||
if (hydrating && dom.getAttribute('class') === next_class_name) {
|
|
||||||
// In case of hydration don't reset the class as it's already correct.
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
|
||||||
dom.__className = next_class_name;
|
|
||||||
} else if (
|
|
||||||
prev_class_name !== next_class_name ||
|
|
||||||
(hydrating && dom.getAttribute('class') !== next_class_name)
|
|
||||||
) {
|
|
||||||
if (next_class_name === '') {
|
|
||||||
dom.removeAttribute('class');
|
|
||||||
} else {
|
|
||||||
dom.setAttribute('class', next_class_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
|
||||||
dom.__className = next_class_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {MathMLElement} dom
|
|
||||||
* @param {string} value
|
|
||||||
* @param {string} [hash]
|
* @param {string} [hash]
|
||||||
* @returns {void}
|
* @param {Record<string, boolean>} [prev_classes]
|
||||||
|
* @param {Record<string, boolean>} [next_classes]
|
||||||
|
* @returns {Record<string, boolean> | undefined}
|
||||||
*/
|
*/
|
||||||
export function set_mathml_class(dom, value, hash) {
|
export function set_class(dom, is_html, value, hash, prev_classes, next_classes) {
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
// @ts-expect-error need to add __className to patched prototype
|
||||||
var prev_class_name = dom.__className;
|
var prev = dom.__className;
|
||||||
var next_class_name = to_class(value, hash);
|
|
||||||
|
if (hydrating || prev !== value) {
|
||||||
if (hydrating && dom.getAttribute('class') === next_class_name) {
|
var next_class_name = to_class(value, hash, next_classes);
|
||||||
// In case of hydration don't reset the class as it's already correct.
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
if (!hydrating || next_class_name !== dom.getAttribute('class')) {
|
||||||
dom.__className = next_class_name;
|
// Removing the attribute when the value is only an empty string causes
|
||||||
} else if (
|
// performance issues vs simply making the className an empty string. So
|
||||||
prev_class_name !== next_class_name ||
|
// we should only remove the class if the the value is nullish
|
||||||
(hydrating && dom.getAttribute('class') !== next_class_name)
|
// and there no hash/directives :
|
||||||
) {
|
if (next_class_name == null) {
|
||||||
if (next_class_name === '') {
|
dom.removeAttribute('class');
|
||||||
dom.removeAttribute('class');
|
} else if (is_html) {
|
||||||
} else {
|
dom.className = next_class_name;
|
||||||
dom.setAttribute('class', next_class_name);
|
} else {
|
||||||
|
dom.setAttribute('class', next_class_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
// @ts-expect-error need to add __className to patched prototype
|
||||||
dom.__className = next_class_name;
|
dom.__className = value;
|
||||||
}
|
} else if (next_classes) {
|
||||||
}
|
prev_classes ??= {};
|
||||||
|
|
||||||
/**
|
for (var key in next_classes) {
|
||||||
* @param {HTMLElement} dom
|
var is_present = !!next_classes[key];
|
||||||
* @param {string} value
|
|
||||||
* @param {string} [hash]
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
export function set_class(dom, value, hash) {
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
|
||||||
var prev_class_name = dom.__className;
|
|
||||||
var next_class_name = to_class(value, hash);
|
|
||||||
|
|
||||||
if (hydrating && dom.className === next_class_name) {
|
if (is_present !== !!prev_classes[key]) {
|
||||||
// In case of hydration don't reset the class as it's already correct.
|
dom.classList.toggle(key, is_present);
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
}
|
||||||
dom.__className = next_class_name;
|
|
||||||
} else if (
|
|
||||||
prev_class_name !== next_class_name ||
|
|
||||||
(hydrating && dom.className !== next_class_name)
|
|
||||||
) {
|
|
||||||
// Removing the attribute when the value is only an empty string causes
|
|
||||||
// peformance issues vs simply making the className an empty string. So
|
|
||||||
// we should only remove the class if the the value is nullish.
|
|
||||||
if (value == null && !hash) {
|
|
||||||
dom.removeAttribute('class');
|
|
||||||
} else {
|
|
||||||
dom.className = next_class_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error need to add __className to patched prototype
|
|
||||||
dom.__className = next_class_name;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return next_classes;
|
||||||
* @template V
|
|
||||||
* @param {V} value
|
|
||||||
* @param {string} [hash]
|
|
||||||
* @returns {string | V}
|
|
||||||
*/
|
|
||||||
function to_class(value, hash) {
|
|
||||||
return (value == null ? '' : value) + (hash ? ' ' + hash : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Element} dom
|
|
||||||
* @param {string} class_name
|
|
||||||
* @param {boolean} value
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
export function toggle_class(dom, class_name, value) {
|
|
||||||
if (value) {
|
|
||||||
if (dom.classList.contains(class_name)) return;
|
|
||||||
dom.classList.add(class_name);
|
|
||||||
} else {
|
|
||||||
if (!dom.classList.contains(class_name)) return;
|
|
||||||
dom.classList.remove(class_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,79 +1,85 @@
|
|||||||
import { run_all } from '../../shared/utils.js';
|
import { run_all } from '../../shared/utils.js';
|
||||||
|
|
||||||
// Fallback for when requestIdleCallback is not available
|
// Fallback for when requestIdleCallback is not available
|
||||||
export const request_idle_callback =
|
const request_idle_callback =
|
||||||
typeof requestIdleCallback === 'undefined'
|
typeof requestIdleCallback === 'undefined'
|
||||||
? (/** @type {() => void} */ cb) => setTimeout(cb, 1)
|
? (/** @type {() => void} */ cb) => setTimeout(cb, 1)
|
||||||
: requestIdleCallback;
|
: requestIdleCallback;
|
||||||
|
|
||||||
let is_micro_task_queued = false;
|
|
||||||
let is_idle_task_queued = false;
|
|
||||||
|
|
||||||
/** @type {Array<() => void>} */
|
/** @type {Array<() => void>} */
|
||||||
let queued_boundary_microtasks = [];
|
let boundary_micro_tasks = [];
|
||||||
|
|
||||||
/** @type {Array<() => void>} */
|
/** @type {Array<() => void>} */
|
||||||
let queued_post_microtasks = [];
|
let micro_tasks = [];
|
||||||
|
|
||||||
/** @type {Array<() => void>} */
|
/** @type {Array<() => void>} */
|
||||||
let queued_idle_tasks = [];
|
let idle_tasks = [];
|
||||||
|
|
||||||
export function flush_boundary_micro_tasks() {
|
function run_boundary_micro_tasks() {
|
||||||
const tasks = queued_boundary_microtasks.slice();
|
var tasks = boundary_micro_tasks;
|
||||||
queued_boundary_microtasks = [];
|
boundary_micro_tasks = [];
|
||||||
run_all(tasks);
|
run_all(tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flush_post_micro_tasks() {
|
function run_post_micro_tasks() {
|
||||||
const tasks = queued_post_microtasks.slice();
|
var tasks = micro_tasks;
|
||||||
queued_post_microtasks = [];
|
micro_tasks = [];
|
||||||
run_all(tasks);
|
run_all(tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flush_idle_tasks() {
|
function run_idle_tasks() {
|
||||||
if (is_idle_task_queued) {
|
var tasks = idle_tasks;
|
||||||
is_idle_task_queued = false;
|
idle_tasks = [];
|
||||||
const tasks = queued_idle_tasks.slice();
|
run_all(tasks);
|
||||||
queued_idle_tasks = [];
|
|
||||||
run_all(tasks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function flush_all_micro_tasks() {
|
function run_micro_tasks() {
|
||||||
if (is_micro_task_queued) {
|
run_boundary_micro_tasks();
|
||||||
is_micro_task_queued = false;
|
run_post_micro_tasks();
|
||||||
flush_boundary_micro_tasks();
|
|
||||||
flush_post_micro_tasks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {() => void} fn
|
* @param {() => void} fn
|
||||||
*/
|
*/
|
||||||
export function queue_boundary_micro_task(fn) {
|
export function queue_boundary_micro_task(fn) {
|
||||||
if (!is_micro_task_queued) {
|
if (boundary_micro_tasks.length === 0 && micro_tasks.length === 0) {
|
||||||
is_micro_task_queued = true;
|
queueMicrotask(run_micro_tasks);
|
||||||
queueMicrotask(flush_all_micro_tasks);
|
|
||||||
}
|
}
|
||||||
queued_boundary_microtasks.push(fn);
|
|
||||||
|
boundary_micro_tasks.push(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {() => void} fn
|
* @param {() => void} fn
|
||||||
*/
|
*/
|
||||||
export function queue_micro_task(fn) {
|
export function queue_micro_task(fn) {
|
||||||
if (!is_micro_task_queued) {
|
if (boundary_micro_tasks.length === 0 && micro_tasks.length === 0) {
|
||||||
is_micro_task_queued = true;
|
queueMicrotask(run_micro_tasks);
|
||||||
queueMicrotask(flush_all_micro_tasks);
|
|
||||||
}
|
}
|
||||||
queued_post_microtasks.push(fn);
|
|
||||||
|
micro_tasks.push(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {() => void} fn
|
* @param {() => void} fn
|
||||||
*/
|
*/
|
||||||
export function queue_idle_task(fn) {
|
export function queue_idle_task(fn) {
|
||||||
if (!is_idle_task_queued) {
|
if (idle_tasks.length === 0) {
|
||||||
is_idle_task_queued = true;
|
request_idle_callback(run_idle_tasks);
|
||||||
request_idle_callback(flush_idle_tasks);
|
}
|
||||||
|
|
||||||
|
idle_tasks.push(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously run any queued tasks.
|
||||||
|
*/
|
||||||
|
export function flush_tasks() {
|
||||||
|
if (boundary_micro_tasks.length > 0 || micro_tasks.length > 0) {
|
||||||
|
run_micro_tasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idle_tasks.length > 0) {
|
||||||
|
run_idle_tasks();
|
||||||
}
|
}
|
||||||
queued_idle_tasks.push(fn);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
<p class=" svelte-xyz">Foo</p>
|
<p class="svelte-xyz">Foo</p>
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { flushSync } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// This test counts mutations on hydration
|
||||||
|
// set_class() should not mutate class on hydration, except if mismatch
|
||||||
|
export default test({
|
||||||
|
mode: ['server', 'hydrate'],
|
||||||
|
|
||||||
|
server_props: {
|
||||||
|
browser: false
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
browser: true
|
||||||
|
},
|
||||||
|
|
||||||
|
html: `
|
||||||
|
<main id="main" class="browser">
|
||||||
|
<div class="custom svelte-1cjqok6 foo bar"></div>
|
||||||
|
<span class="svelte-1cjqok6 foo bar"></span>
|
||||||
|
<b class="custom foo bar"></b>
|
||||||
|
<i class="foo bar"></i>
|
||||||
|
</main>
|
||||||
|
`,
|
||||||
|
|
||||||
|
ssrHtml: `
|
||||||
|
<main id="main">
|
||||||
|
<div class="custom svelte-1cjqok6 foo bar"></div>
|
||||||
|
<span class="svelte-1cjqok6 foo bar"></span>
|
||||||
|
<b class="custom foo bar"></b>
|
||||||
|
<i class="foo bar"></i>
|
||||||
|
</main>
|
||||||
|
`,
|
||||||
|
|
||||||
|
async test({ assert, component, instance }) {
|
||||||
|
flushSync();
|
||||||
|
assert.deepEqual(instance.get_and_clear_mutations(), ['MAIN']);
|
||||||
|
|
||||||
|
component.foo = false;
|
||||||
|
flushSync();
|
||||||
|
assert.deepEqual(instance.get_and_clear_mutations(), ['DIV', 'SPAN', 'B', 'I']);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
<script>
|
||||||
|
let {
|
||||||
|
classname = 'custom',
|
||||||
|
foo = true,
|
||||||
|
bar = true,
|
||||||
|
browser
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
let mutations = [];
|
||||||
|
let observer;
|
||||||
|
|
||||||
|
if (browser) {
|
||||||
|
observer = new MutationObserver(update_mutation_records);
|
||||||
|
observer.observe(document.querySelector('#main'), { attributes: true, subtree: true });
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
return () => observer.disconnect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_mutation_records(results) {
|
||||||
|
for (const r of results) {
|
||||||
|
mutations.push(r.target.nodeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_and_clear_mutations() {
|
||||||
|
update_mutation_records(observer.takeRecords());
|
||||||
|
const result = mutations;
|
||||||
|
mutations = [];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<main id="main" class:browser>
|
||||||
|
<div class={classname} class:foo class:bar></div>
|
||||||
|
<span class:foo class:bar></span>
|
||||||
|
<b class={classname} class:foo class:bar></b>
|
||||||
|
<i class:foo class:bar></i>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div,
|
||||||
|
span {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
import { flushSync } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
html: `
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0 bar"></div>
|
||||||
|
<span class="foo bar"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0 bar"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 bar"></div>
|
||||||
|
<span class="bar"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 bar"></span></div>
|
||||||
|
|
||||||
|
<div class="football svelte-tza1s0 bar"></div>
|
||||||
|
<span class="football bar"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="football svelte-tza1s0 bar"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 bar not-foo"></div>
|
||||||
|
<span class="bar not-foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 bar not-foo"></span></div>
|
||||||
|
|
||||||
|
`,
|
||||||
|
test({ assert, target, component }) {
|
||||||
|
component.foo = true;
|
||||||
|
flushSync();
|
||||||
|
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0 bar"></div>
|
||||||
|
<span class="foo bar"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0 bar"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 foo"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 foo"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 bar foo"></div>
|
||||||
|
<span class="bar foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 bar foo"></span></div>
|
||||||
|
|
||||||
|
<div class="football svelte-tza1s0 bar foo"></div>
|
||||||
|
<span class="football bar foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="football svelte-tza1s0 bar foo"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 bar foo"></div>
|
||||||
|
<span class="bar foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 bar foo"></span></div>
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
component.bar = false;
|
||||||
|
flushSync();
|
||||||
|
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 foo"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 foo"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 foo"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 foo"></span></div>
|
||||||
|
|
||||||
|
<div class="football svelte-tza1s0 foo"></div>
|
||||||
|
<span class="football foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="football svelte-tza1s0 foo"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 foo"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 foo"></span></div>
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
component.foo = false;
|
||||||
|
flushSync();
|
||||||
|
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="foo svelte-tza1s0"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="foo svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span class=""></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0"></div>
|
||||||
|
<span class=""></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="football svelte-tza1s0"></div>
|
||||||
|
<span class="football"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="football svelte-tza1s0"></span></div>
|
||||||
|
|
||||||
|
<div class="svelte-tza1s0 not-foo"></div>
|
||||||
|
<span class="not-foo"></span>
|
||||||
|
<div class="svelte-tza1s0"><span class="svelte-tza1s0 not-foo"></span></div>
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<script>
|
||||||
|
let { foo = false, bar = true } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div></div>
|
||||||
|
<span></span>
|
||||||
|
<div><span></span></div>
|
||||||
|
|
||||||
|
<div class="foo"></div>
|
||||||
|
<span class="foo"></span>
|
||||||
|
<div><span class="foo"></span></div>
|
||||||
|
|
||||||
|
<div class="foo" class:bar></div>
|
||||||
|
<span class="foo" class:bar></span>
|
||||||
|
<div><span class="foo" class:bar></span></div>
|
||||||
|
|
||||||
|
<div class="foo" class:foo></div>
|
||||||
|
<span class="foo" class:foo></span>
|
||||||
|
<div><span class="foo" class:foo></span></div>
|
||||||
|
|
||||||
|
<div class="foo" class:bar class:foo></div>
|
||||||
|
<span class="foo" class:bar class:foo></span>
|
||||||
|
<div><span class="foo" class:bar class:foo></span></div>
|
||||||
|
|
||||||
|
<div class="football" class:bar class:foo></div>
|
||||||
|
<span class="football" class:bar class:foo></span>
|
||||||
|
<div><span class="football" class:bar class:foo></span></div>
|
||||||
|
|
||||||
|
<div class="foo" class:bar class:foo class:not-foo={!foo}></div>
|
||||||
|
<span class="foo" class:bar class:foo class:not-foo={!foo}></span>
|
||||||
|
<div><span class="foo" class:bar class:foo class:not-foo={!foo}></span></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
div > span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,3 +0,0 @@
|
|||||||
import { test } from '../../test';
|
|
||||||
|
|
||||||
export default test({});
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{#key 'key'}
|
||||||
|
{@const foo = 'bar'}
|
||||||
|
{/key}
|
||||||
Loading…
Reference in new issue