diff --git a/src/compile/nodes/Animation.ts b/src/compile/nodes/Animation.ts index 4df3fec66f..8a52a05ecd 100644 --- a/src/compile/nodes/Animation.ts +++ b/src/compile/nodes/Animation.ts @@ -20,13 +20,6 @@ export default class Animation extends Node { }); } - if (!component.animations.has(this.name)) { - component.error(this, { - code: `missing-animation`, - message: `Missing animation '${this.name}'` - }); - } - const block = parent.parent; if (!block || block.type !== 'EachBlock' || !block.key) { // TODO can we relax the 'immediate child' rule? diff --git a/src/compile/render-dom/Block.ts b/src/compile/render-dom/Block.ts index 40c8742abc..4f6f91fb9c 100644 --- a/src/compile/render-dom/Block.ts +++ b/src/compile/render-dom/Block.ts @@ -381,7 +381,7 @@ export default class Block { return deindent` ${this.comment && `// ${escape(this.comment)}`} - function ${this.name}(#component${this.key ? `, ${localKey}` : ''}, ctx) { + function ${this.name}(${this.key ? `${localKey}, ` : ''}ctx) { ${this.getContents(localKey)} } `.replace(/(#+)(\w*)/g, (match: string, sigil: string, name: string) => { diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index a04248ff5d..ac2542d86e 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -125,6 +125,17 @@ export default function dom( __create_fragment(ctx) { ${block.getContents()} } + + ${component.exports.map(x => deindent` + get ${x.as}() { + return this.__get_state().${x.name}; + } + + set ${x.as}(value) { + this.__set('${x.name}', value); + @flush(); + } + `)} } `); } diff --git a/src/compile/render-dom/wrappers/EachBlock.ts b/src/compile/render-dom/wrappers/EachBlock.ts index b9e33bf52d..c1de0aebd9 100644 --- a/src/compile/render-dom/wrappers/EachBlock.ts +++ b/src/compile/render-dom/wrappers/EachBlock.ts @@ -209,7 +209,7 @@ export default class EachBlockWrapper extends Wrapper { // TODO neaten this up... will end up with an empty line in the block block.builders.init.addBlock(deindent` if (!${this.vars.each_block_value}.${length}) { - ${each_block_else} = ${this.else.block.name}(#component, ctx); + ${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else}.c(); } `); @@ -227,7 +227,7 @@ export default class EachBlockWrapper extends Wrapper { if (!${this.vars.each_block_value}.${length} && ${each_block_else}) { ${each_block_else}.p(changed, ctx); } else if (!${this.vars.each_block_value}.${length}) { - ${each_block_else} = ${this.else.block.name}(#component, ctx); + ${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else}.c(); ${each_block_else}.${mountOrIntro}(${initialMountNode}, ${this.vars.anchor}); } else if (${each_block_else}) { @@ -243,7 +243,7 @@ export default class EachBlockWrapper extends Wrapper { ${each_block_else} = null; } } else if (!${each_block_else}) { - ${each_block_else} = ${this.else.block.name}(#component, ctx); + ${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else}.c(); ${each_block_else}.${mountOrIntro}(${initialMountNode}, ${this.vars.anchor}); } @@ -300,7 +300,7 @@ export default class EachBlockWrapper extends Wrapper { for (var #i = 0; #i < ${this.vars.each_block_value}.${length}; #i += 1) { let child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i); let key = ${get_key}(child_ctx); - ${blocks}[#i] = ${lookup}[key] = ${create_each_block}(#component, key, child_ctx); + ${blocks}[#i] = ${lookup}[key] = ${create_each_block}(key, child_ctx); } `); @@ -336,7 +336,7 @@ export default class EachBlockWrapper extends Wrapper { ${this.block.hasOutros && `@groupOutros();`} ${this.node.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].r();`} - ${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.vars.each_block_value}, ${lookup}, ${updateMountNode}, ${destroy}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.vars.get_each_context}); + ${blocks} = @updateKeyedEach(${blocks}, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.vars.each_block_value}, ${lookup}, ${updateMountNode}, ${destroy}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.vars.get_each_context}); ${this.node.hasAnimation && `for (let #i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].a();`} `); @@ -371,7 +371,7 @@ export default class EachBlockWrapper extends Wrapper { var ${iterations} = []; for (var #i = 0; #i < ${this.vars.each_block_value}.${length}; #i += 1) { - ${iterations}[#i] = ${create_each_block}(#component, ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i)); + ${iterations}[#i] = ${create_each_block}(${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i)); } `); @@ -434,7 +434,7 @@ export default class EachBlockWrapper extends Wrapper { if (${iterations}[#i]) { ${iterations}[#i].p(changed, child_ctx); } else { - ${iterations}[#i] = ${create_each_block}(#component, child_ctx); + ${iterations}[#i] = ${create_each_block}(child_ctx); ${iterations}[#i].c(); } ${iterations}[#i].i(${updateMountNode}, ${anchor}); @@ -443,13 +443,13 @@ export default class EachBlockWrapper extends Wrapper { if (${iterations}[#i]) { ${iterations}[#i].p(changed, child_ctx); } else { - ${iterations}[#i] = ${create_each_block}(#component, child_ctx); + ${iterations}[#i] = ${create_each_block}(child_ctx); ${iterations}[#i].c(); ${iterations}[#i].m(${updateMountNode}, ${anchor}); } ` : deindent` - ${iterations}[#i] = ${create_each_block}(#component, child_ctx); + ${iterations}[#i] = ${create_each_block}(child_ctx); ${iterations}[#i].c(); ${iterations}[#i].${mountOrIntro}(${updateMountNode}, ${anchor}); `; diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index c2bf6b0434..7eed9dd073 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -806,7 +806,7 @@ export default class ElementWrapper extends Wrapper { const params = this.node.animation.expression ? this.node.animation.expression.snippet : '{}'; block.builders.animate.addBlock(deindent` if (${animation}) ${animation}.stop(); - ${animation} = @wrapAnimation(${this.var}, ${rect}, %animations-${this.node.animation.name}, ${params}); + ${animation} = @wrapAnimation(${this.var}, ${rect}, ctx.${this.node.animation.name}, ${params}); `); } diff --git a/src/internal/animations.js b/src/internal/animations.js new file mode 100644 index 0000000000..355c0254e7 --- /dev/null +++ b/src/internal/animations.js @@ -0,0 +1,102 @@ +import { transitionManager, linear, generateRule, hash } from './transitions.js'; + +export function wrapAnimation(node, from, fn, params) { + if (!from) return; + + const to = node.getBoundingClientRect(); + if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) return; + + const info = fn(node, { from, to }, params); + + const duration = 'duration' in info ? info.duration : 300; + const delay = 'delay' in info ? info.delay : 0; + const ease = info.easing || linear; + const start = window.performance.now() + delay; + const end = start + duration; + + const program = { + a: 0, + t: 0, + b: 1, + delta: 1, + duration, + start, + end + }; + + const cssText = node.style.cssText; + + const animation = { + pending: delay ? program : null, + program: delay ? null : program, + running: true, + + start() { + if (info.css) { + if (delay) node.style.cssText = cssText; + + const rule = generateRule(program, ease, info.css); + program.name = `__svelte_${hash(rule)}`; + + transitionManager.addRule(rule, program.name); + + node.style.animation = (node.style.animation || '') + .split(', ') + .filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim))) + .concat(`${program.name} ${program.duration}ms linear 1 forwards`) + .join(', '); + } + + animation.program = program; + animation.pending = null; + }, + + update: now => { + const p = now - program.start; + const t = program.a + program.delta * ease(p / program.duration); + if (info.tick) info.tick(t, 1 - t); + }, + + done() { + if (info.tick) info.tick(1, 0); + animation.stop(); + }, + + stop() { + if (info.css) transitionManager.deleteRule(node, program.name); + animation.running = false; + } + }; + + transitionManager.add(animation); + + if (info.tick) info.tick(0, 1); + + if (delay) { + if (info.css) node.style.cssText += info.css(0, 1); + } else { + animation.start(); + } + + return animation; +} + +export function fixPosition(node) { + const style = getComputedStyle(node); + + if (style.position !== 'absolute' && style.position !== 'fixed') { + const { width, height } = style; + const a = node.getBoundingClientRect(); + node.style.position = 'absolute'; + node.style.width = width; + node.style.height = height; + const b = node.getBoundingClientRect(); + + if (a.left !== b.left || a.top !== b.top) { + const style = getComputedStyle(node); + const transform = style.transform === 'none' ? '' : style.transform; + + node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`; + } + } +} \ No newline at end of file diff --git a/src/internal/await-block.js b/src/internal/await-block.js new file mode 100644 index 0000000000..ed4b2ccf26 --- /dev/null +++ b/src/internal/await-block.js @@ -0,0 +1,60 @@ +import { assign, isPromise } from './utils.js'; +import { groupOutros } from './transitions.js'; + +export function handlePromise(promise, info) { + var token = info.token = {}; + + function update(type, index, key, value) { + if (info.token !== token) return; + + info.resolved = key && { [key]: value }; + + const child_ctx = assign(assign({}, info.ctx), info.resolved); + const block = type && (info.current = type)(info.component, child_ctx); + + if (info.block) { + if (info.blocks) { + info.blocks.forEach((block, i) => { + if (i !== index && block) { + groupOutros(); + block.o(() => { + block.d(1); + info.blocks[i] = null; + }); + } + }); + } else { + info.block.d(1); + } + + block.c(); + block[block.i ? 'i' : 'm'](info.mount(), info.anchor); + + info.component.root.set({}); // flush any handlers that were created + } + + info.block = block; + if (info.blocks) info.blocks[index] = block; + } + + if (isPromise(promise)) { + promise.then(value => { + update(info.then, 1, info.value, value); + }, error => { + update(info.catch, 2, info.error, error); + }); + + // if we previously had a then/catch block, destroy it + if (info.current !== info.pending) { + update(info.pending, 0); + return true; + } + } else { + if (info.current !== info.then) { + update(info.then, 1, info.value, promise); + return true; + } + + info.resolved = { [info.value]: promise }; + } +} \ No newline at end of file diff --git a/src/internal/index.js b/src/internal/index.js index e1dc837d56..037607e487 100644 --- a/src/internal/index.js +++ b/src/internal/index.js @@ -1,5 +1,10 @@ +export * from './animations.js'; +export * from './await-block.js'; export * from './dom.js'; +export * from './keyed-each.js'; export * from './scheduler.js'; +export * from './spread.js'; +export * from './ssr.js'; export * from './transitions.js'; export * from './utils.js'; export * from './SvelteComponent.js'; \ No newline at end of file diff --git a/src/internal/keyed-each.js b/src/internal/keyed-each.js new file mode 100644 index 0000000000..b68a40e11d --- /dev/null +++ b/src/internal/keyed-each.js @@ -0,0 +1,123 @@ +export function destroyBlock(block, lookup) { + block.d(1); + lookup[block.key] = null; +} + +export function outroAndDestroyBlock(block, lookup) { + block.o(function() { + destroyBlock(block, lookup); + }); +} + +export function fixAndOutroAndDestroyBlock(block, lookup) { + block.f(); + outroAndDestroyBlock(block, lookup); +} + +export function updateKeyedEach(old_blocks, changed, get_key, dynamic, ctx, list, lookup, node, destroy, create_each_block, intro_method, next, get_context) { + var o = old_blocks.length; + var n = list.length; + + var i = o; + var old_indexes = {}; + while (i--) old_indexes[old_blocks[i].key] = i; + + var new_blocks = []; + var new_lookup = {}; + var deltas = {}; + + var i = n; + while (i--) { + var child_ctx = get_context(ctx, list, i); + var key = get_key(child_ctx); + var block = lookup[key]; + + if (!block) { + block = create_each_block(key, child_ctx); + block.c(); + } else if (dynamic) { + block.p(changed, child_ctx); + } + + new_blocks[i] = new_lookup[key] = block; + + if (key in old_indexes) deltas[key] = Math.abs(i - old_indexes[key]); + } + + var will_move = {}; + var did_move = {}; + + function insert(block) { + block[intro_method](node, next); + lookup[block.key] = block; + next = block.first; + n--; + } + + while (o && n) { + var new_block = new_blocks[n - 1]; + var old_block = old_blocks[o - 1]; + var new_key = new_block.key; + var old_key = old_block.key; + + if (new_block === old_block) { + // do nothing + next = new_block.first; + o--; + n--; + } + + else if (!new_lookup[old_key]) { + // remove old block + destroy(old_block, lookup); + o--; + } + + else if (!lookup[new_key] || will_move[new_key]) { + insert(new_block); + } + + else if (did_move[old_key]) { + o--; + + } else if (deltas[new_key] > deltas[old_key]) { + did_move[new_key] = true; + insert(new_block); + + } else { + will_move[old_key] = true; + o--; + } + } + + while (o--) { + var old_block = old_blocks[o]; + if (!new_lookup[old_block.key]) destroy(old_block, lookup); + } + + while (n) insert(new_blocks[n - 1]); + + return new_blocks; +} + +export function measure(blocks) { + const rects = {}; + let i = blocks.length; + while (i--) rects[blocks[i].key] = blocks[i].node.getBoundingClientRect(); + return rects; +} + +export function animate(blocks, rects, fn, params) { + let i = blocks.length; + while (i--) { + const block = blocks[i]; + const from = rects[block.key]; + + if (!from) continue; + const to = block.node.getBoundingClientRect(); + + if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) continue; + + + } +} \ No newline at end of file diff --git a/src/internal/spread.js b/src/internal/spread.js new file mode 100644 index 0000000000..2ecc432fc3 --- /dev/null +++ b/src/internal/spread.js @@ -0,0 +1,37 @@ +export function getSpreadUpdate(levels, updates) { + var update = {}; + + var to_null_out = {}; + var accounted_for = {}; + + var i = levels.length; + while (i--) { + var o = levels[i]; + var n = updates[i]; + + if (n) { + for (var key in o) { + if (!(key in n)) to_null_out[key] = 1; + } + + for (var key in n) { + if (!accounted_for[key]) { + update[key] = n[key]; + accounted_for[key] = 1; + } + } + + levels[i] = n; + } else { + for (var key in o) { + accounted_for[key] = 1; + } + } + } + + for (var key in to_null_out) { + if (!(key in update)) update[key] = undefined; + } + + return update; +} \ No newline at end of file diff --git a/src/internal/ssr.js b/src/internal/ssr.js new file mode 100644 index 0000000000..021d79aeed --- /dev/null +++ b/src/internal/ssr.js @@ -0,0 +1,63 @@ +// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 +// https://infra.spec.whatwg.org/#noncharacter +export const invalidAttributeNameCharacter = /[\s'">\/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; + +export function spread(args) { + const attributes = Object.assign({}, ...args); + let str = ''; + + Object.keys(attributes).forEach(name => { + if (invalidAttributeNameCharacter.test(name)) return; + + const value = attributes[name]; + if (value === undefined) return; + if (value === true) str += " " + name; + + const escaped = String(value) + .replace(/"/g, '"') + .replace(/'/g, '''); + + str += " " + name + "=" + JSON.stringify(escaped); + }); + + return str; +} + +export const escaped = { + '"': '"', + "'": ''', + '&': '&', + '<': '<', + '>': '>' +}; + +export function escape(html) { + return String(html).replace(/["'&<>]/g, match => escaped[match]); +} + +export function each(items, assign, fn) { + let str = ''; + for (let i = 0; i < items.length; i += 1) { + str += fn(assign(items[i], i)); + } + return str; +} + +export const missingComponent = { + _render: () => '' +}; + +export function validateSsrComponent(component, name) { + if (!component || !component._render) { + if (name === 'svelte:component') name += ' this={...}'; + throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules`); + } + + return component; +} + +export function debug(file, line, column, values) { + console.log(`{@debug} ${file ? file + ' ' : ''}(${line}:${column})`); + console.log(values); + return ''; +} \ No newline at end of file diff --git a/src/internal/utils.js b/src/internal/utils.js index 2077c25e01..cf20832c31 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.js @@ -35,4 +35,8 @@ export function exclude(src, prop) { export function run(fn) { fn(); +} + +export function blankObject() { + return Object.create(null); } \ No newline at end of file diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 31f773b431..3ba5f8950a 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -414,6 +414,7 @@ function readAttribute(parser: Parser, uniqueNames: Set) { function get_directive_type(name) { if (name === 'use') return 'Action'; if (name === 'on') return 'EventHandler'; + if (name === 'animate') return 'Animation'; throw new Error(`TODO directive ${name}`); } diff --git a/test/runtime/index.js b/test/runtime/index.js index ddbb27db5d..155c1888cb 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -71,7 +71,6 @@ describe.only("runtime", () => { compileOptions = config.compileOptions || {}; compileOptions.shared = internal; compileOptions.hydratable = hydrate; - compileOptions.store = !!config.store; compileOptions.immutable = config.immutable; compileOptions.skipIntroByDefault = config.skipIntroByDefault; compileOptions.nestedTransitions = config.nestedTransitions; @@ -116,7 +115,7 @@ describe.only("runtime", () => { try { SvelteComponent = require(`./samples/${dir}/main.html`); } catch (err) { - showOutput(cwd, { internal, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile); // eslint-disable-line no-console + showOutput(cwd, { internal, format: 'cjs', hydratable: hydrate, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile); // eslint-disable-line no-console throw err; } diff --git a/test/runtime/samples/action-update/main.html b/test/runtime/samples/action-update/main.html index abeec0dbcb..440ac55c34 100644 --- a/test/runtime/samples/action-update/main.html +++ b/test/runtime/samples/action-update/main.html @@ -2,7 +2,6 @@ export let text = 'Perform an Action'; function checkForCtrl(event) { - console.log(`!!! ${event.ctrlKey}`); if (event.ctrlKey) { text = 'Perform an augmented Action'; } else { diff --git a/test/runtime/samples/animation-css/_config.js b/test/runtime/samples/animation-css/_config.js index 033346342e..f8aa2388cf 100644 --- a/test/runtime/samples/animation-css/_config.js +++ b/test/runtime/samples/animation-css/_config.js @@ -1,5 +1,5 @@ export default { - data: { + props: { things: [ { id: 1, name: 'a' }, { id: 2, name: 'b' }, @@ -33,15 +33,13 @@ export default { }; }) - component.set({ - things: [ - { id: 5, name: 'e' }, - { id: 2, name: 'b' }, - { id: 3, name: 'c' }, - { id: 4, name: 'd' }, - { id: 1, name: 'a' } - ] - }); + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; divs = document.querySelectorAll('div'); assert.ok(~divs[0].style.animation.indexOf('__svelte')); diff --git a/test/runtime/samples/animation-js-delay/_config.js b/test/runtime/samples/animation-js-delay/_config.js index eb0c7863e3..79f6e6e07b 100644 --- a/test/runtime/samples/animation-js-delay/_config.js +++ b/test/runtime/samples/animation-js-delay/_config.js @@ -1,5 +1,5 @@ export default { - data: { + props: { things: [ { id: 1, name: 'a' }, { id: 2, name: 'b' }, @@ -33,15 +33,13 @@ export default { }; }) - component.set({ - things: [ - { id: 5, name: 'e' }, - { id: 2, name: 'b' }, - { id: 3, name: 'c' }, - { id: 4, name: 'd' }, - { id: 1, name: 'a' } - ] - }); + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; divs = document.querySelectorAll('div'); assert.equal(divs[0].dy, 120); diff --git a/test/runtime/samples/animation-js-delay/main.html b/test/runtime/samples/animation-js-delay/main.html index a7fb2f1a85..32c05ad08f 100644 --- a/test/runtime/samples/animation-js-delay/main.html +++ b/test/runtime/samples/animation-js-delay/main.html @@ -17,5 +17,5 @@ {#each things as thing, i (thing.id)} -
{thing.name}
+
{thing.name}
{/each} \ No newline at end of file diff --git a/test/runtime/samples/animation-js/_config.js b/test/runtime/samples/animation-js/_config.js index fbc2e987ed..cb7c6fe394 100644 --- a/test/runtime/samples/animation-js/_config.js +++ b/test/runtime/samples/animation-js/_config.js @@ -1,5 +1,5 @@ export default { - data: { + props: { things: [ { id: 1, name: 'a' }, { id: 2, name: 'b' }, @@ -33,15 +33,13 @@ export default { }; }) - component.set({ - things: [ - { id: 5, name: 'e' }, - { id: 2, name: 'b' }, - { id: 3, name: 'c' }, - { id: 4, name: 'd' }, - { id: 1, name: 'a' } - ] - }); + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; divs = document.querySelectorAll('div'); assert.equal(divs[0].dy, 120); diff --git a/test/runtime/samples/attribute-boolean-indeterminate/_config.js b/test/runtime/samples/attribute-boolean-indeterminate/_config.js index 33acd07948..f30b577a5a 100644 --- a/test/runtime/samples/attribute-boolean-indeterminate/_config.js +++ b/test/runtime/samples/attribute-boolean-indeterminate/_config.js @@ -3,7 +3,7 @@ export default { // so it can't be server-rendered 'skip-ssr': true, - data: { + props: { indeterminate: true }, @@ -15,7 +15,7 @@ export default { const input = target.querySelector('input'); assert.ok(input.indeterminate); - component.set({ indeterminate: false }); + component.indeterminate = false; assert.ok(!input.indeterminate); } }; \ No newline at end of file