diff --git a/site/content/examples/19-7guis/05-7guis-crud/App.svelte b/site/content/examples/19-7guis/05-7guis-crud/App.svelte index 1f39fe6642..a0d6ef7f3e 100644 --- a/site/content/examples/19-7guis/05-7guis-crud/App.svelte +++ b/site/content/examples/19-7guis/05-7guis-crud/App.svelte @@ -30,10 +30,7 @@ $: selected = filteredPeople[i]; - $: { - first = selected ? selected.first : ''; - last = selected ? selected.last : ''; - } + $: reset_inputs(selected); function create() { people = people.concat({ first, last }); @@ -53,7 +50,8 @@ } function reset_inputs(person) { - ({ first, last } = person); + first = person ? person.first : ''; + last = person ? person.last : ''; } diff --git a/site/content/tutorial/12-actions/01-actions/text.md b/site/content/tutorial/12-actions/01-actions/text.md index 279dc3123f..38de8f9a65 100644 --- a/site/content/tutorial/12-actions/01-actions/text.md +++ b/site/content/tutorial/12-actions/01-actions/text.md @@ -27,7 +27,7 @@ import { pannable } from './pannable.js'; > ``` -Open the `pannable.js` file. Like transition functions, an action function receives a `node` and some optional parameters, and returns an action object. That object must have a `destroy` function, which is called when the element is unmounted. +Open the `pannable.js` file. Like transition functions, an action function receives a `node` and some optional parameters, and returns an action object. That object can have a `destroy` function, which is called when the element is unmounted. We want to fire `panstart` event when the user mouses down on the element, `panmove` events (with `dx` and `dy` properties showing how far the mouse moved) when they drag it, and `panend` events when they mouse up. One possible implementation looks like this: @@ -84,4 +84,3 @@ export function pannable(node) { Update the `pannable` function and try moving the box around. > This implementation is for demonstration purposes — a more complete one would also consider touch events. - diff --git a/site/src/routes/faq.js b/site/src/routes/faq.js new file mode 100644 index 0000000000..6263494a4c --- /dev/null +++ b/site/src/routes/faq.js @@ -0,0 +1,4 @@ +export function get(req, res) { + res.writeHead(302, { Location: 'https://github.com/sveltejs/svelte/wiki/FAQ' }); + res.end(); +} \ No newline at end of file diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index 19da4bcc1e..1b2d82188c 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -548,7 +548,7 @@ export default class Element extends Node { message: `'group' binding can only be used with or ` }); } - } else if (name == 'files') { + } else if (name === 'files') { if (this.name !== 'input') { component.error(binding, { code: `invalid-binding`, @@ -564,6 +564,14 @@ export default class Element extends Node { message: `'files' binding can only be used with ` }); } + + } else if (name === 'open') { + if (this.name !== 'details') { + component.error(binding, { + code: `invalid-binding`, + message: `'${name}' binding can only be used with
` + }); + } } else if ( name === 'currentTime' || name === 'duration' || diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 350459c683..41db1c03a0 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -90,6 +90,12 @@ const events = [ name === 'playbackRate' }, + // details event + { + event_names: ['toggle'], + filter: (node: Element, name: string) => + node.name === 'details' + }, ]; export default class ElementWrapper extends Wrapper { @@ -455,7 +461,7 @@ export default class ElementWrapper extends Wrapper { function ${handler}() { ${animation_frame && deindent` cancelAnimationFrame(${animation_frame}); - if (!${this.var}.paused) ${animation_frame} = requestAnimationFrame(${handler});`} + if (!${this.var}.paused) ${animation_frame} = @raf(${handler});`} ${needs_lock && `${lock} = true;`} ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''}); } diff --git a/src/internal/loop.js b/src/internal/loop.js index 8150727441..60c7df4d70 100644 --- a/src/internal/loop.js +++ b/src/internal/loop.js @@ -1,4 +1,4 @@ -import { now } from './utils.js'; +import { now, raf } from './utils.js'; const tasks = new Set(); let running = false; @@ -12,7 +12,7 @@ function run_tasks() { }); running = tasks.size > 0; - if (running) requestAnimationFrame(run_tasks); + if (running) raf(run_tasks); } export function clear_loops() { @@ -26,7 +26,7 @@ export function loop(fn) { if (!running) { running = true; - requestAnimationFrame(run_tasks); + raf(run_tasks); } return { diff --git a/src/internal/style_manager.js b/src/internal/style_manager.js index d71e922f01..3679470399 100644 --- a/src/internal/style_manager.js +++ b/src/internal/style_manager.js @@ -1,4 +1,5 @@ import { element } from './dom.js'; +import { raf } from './utils.js'; let stylesheet; let active = 0; @@ -56,7 +57,7 @@ export function delete_rule(node, name) { } export function clear_rules() { - requestAnimationFrame(() => { + raf(() => { if (active) return; let i = stylesheet.cssRules.length; while (i--) stylesheet.deleteRule(i); diff --git a/src/internal/utils.js b/src/internal/utils.js index e6d66d8717..7823a5b920 100644 --- a/src/internal/utils.js +++ b/src/internal/utils.js @@ -80,11 +80,19 @@ export function exclude_internal_props(props) { return result; } -export let now = typeof window !== 'undefined' +const is_client = typeof window !== 'undefined'; + +export let now = is_client ? () => window.performance.now() : () => Date.now(); +export let raf = is_client ? requestAnimationFrame : noop; + // used internally for testing export function set_now(fn) { now = fn; +} + +export function set_raf(fn) { + raf = fn; } \ No newline at end of file diff --git a/test/js/samples/bind-open/expected.js b/test/js/samples/bind-open/expected.js new file mode 100644 index 0000000000..7c73c8ddac --- /dev/null +++ b/test/js/samples/bind-open/expected.js @@ -0,0 +1,69 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponent, + detach, + element, + init, + insert, + listen, + noop, + safe_not_equal +} from "svelte/internal"; + +function create_fragment(ctx) { + var details, dispose; + + return { + c() { + details = element("details"); + details.innerHTML = `summarycontent + `; + dispose = listen(details, "toggle", ctx.details_toggle_handler); + }, + + m(target, anchor) { + insert(target, details, anchor); + + details.open = ctx.open; + }, + + p(changed, ctx) { + if (changed.open) details.open = ctx.open; + }, + + i: noop, + o: noop, + + d(detaching) { + if (detaching) { + detach(details); + } + + dispose(); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + let { open } = $$props; + + function details_toggle_handler() { + open = this.open; + $$invalidate('open', open); + } + + $$self.$set = $$props => { + if ('open' in $$props) $$invalidate('open', open = $$props.open); + }; + + return { open, details_toggle_handler }; +} + +class Component extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, ["open"]); + } +} + +export default Component; diff --git a/test/js/samples/bind-open/input.svelte b/test/js/samples/bind-open/input.svelte new file mode 100644 index 0000000000..3dd2b03a73 --- /dev/null +++ b/test/js/samples/bind-open/input.svelte @@ -0,0 +1,7 @@ + + +
+ summarycontent +
diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js index 153f92bad8..51d8bf63a3 100644 --- a/test/js/samples/debug-hoisted/expected.js +++ b/test/js/samples/debug-hoisted/expected.js @@ -53,4 +53,4 @@ class Component extends SvelteComponentDev { } } -export default Component; +export default Component; \ No newline at end of file diff --git a/test/js/samples/media-bindings/expected.js b/test/js/samples/media-bindings/expected.js index 8a193f698b..f45f9ce8db 100644 --- a/test/js/samples/media-bindings/expected.js +++ b/test/js/samples/media-bindings/expected.js @@ -8,6 +8,7 @@ import { insert, listen, noop, + raf, run_all, safe_not_equal, time_ranges_to_array @@ -18,7 +19,7 @@ function create_fragment(ctx) { function audio_timeupdate_handler() { cancelAnimationFrame(audio_animationframe); - if (!audio.paused) audio_animationframe = requestAnimationFrame(audio_timeupdate_handler); + if (!audio.paused) audio_animationframe = raf(audio_timeupdate_handler); audio_updating = true; ctx.audio_timeupdate_handler.call(audio); } diff --git a/test/runtime/index.js b/test/runtime/index.js index db02ce13d4..fd5ffdef04 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -3,7 +3,7 @@ import * as path from "path"; import * as fs from "fs"; import { rollup } from 'rollup'; import * as virtual from 'rollup-plugin-virtual'; -import { clear_loops, set_now } from "../../internal.js"; +import { clear_loops, set_now, set_raf } from "../../internal.js"; import { showOutput, @@ -101,7 +101,7 @@ describe("runtime", () => { } }; set_now(() => raf.time); - global.requestAnimationFrame = cb => { + set_raf(cb => { let called = false; raf.callback = () => { if (!called) { @@ -109,7 +109,7 @@ describe("runtime", () => { cb(); } }; - }; + }); try { mod = require(`./samples/${dir}/main.svelte`); diff --git a/test/runtime/samples/binding-details-open/_config.js b/test/runtime/samples/binding-details-open/_config.js new file mode 100644 index 0000000000..cf2459c3f1 --- /dev/null +++ b/test/runtime/samples/binding-details-open/_config.js @@ -0,0 +1,25 @@ +export default { + html: ` +
toggle
+ `, + + async test({ assert, component, target, window }) { + const details = target.querySelector('details'); + const event = new window.Event('toggle'); + + details.open = true; + await details.dispatchEvent(event); + assert.equal(component.visible, true); + assert.htmlEqual(target.innerHTML, ` +
toggle
+

hello!

+ `); + + details.open = false; + await details.dispatchEvent(event); + assert.equal(component.visible, false); + assert.htmlEqual(target.innerHTML, ` +
toggle
+ `); + } +}; diff --git a/test/runtime/samples/binding-details-open/main.svelte b/test/runtime/samples/binding-details-open/main.svelte new file mode 100644 index 0000000000..3a7a08e121 --- /dev/null +++ b/test/runtime/samples/binding-details-open/main.svelte @@ -0,0 +1,9 @@ + + +
toggle
+ +{#if visible} +

hello!

+{/if}