Merge branch 'master' into a11y-no-noninteractive-element-to-interactive-role

pull/8167/head
Nguyen Tran 4 years ago
commit 80f8650439

@ -4,9 +4,10 @@
* Add a11y warnings: * Add a11y warnings:
* `aria-activedescendant-has-tabindex`: elements with `aria-activedescendant` need to have a `tabindex` ([#8172](https://github.com/sveltejs/svelte/pull/8172)) * `aria-activedescendant-has-tabindex`: elements with `aria-activedescendant` need to have a `tabindex` ([#8172](https://github.com/sveltejs/svelte/pull/8172))
* * `role-supports-aria-props`: checks that the (implicit) element role supports the given aria attributes ([#8195](https://github.com/sveltejs/svelte/pull/8195))
* Omit a11y warning on `<video>` tags with `aria-hidden="true"` ([#7874](https://github.com/sveltejs/svelte/issues/7874)) * Omit a11y warning on `<video>` tags with `aria-hidden="true"` ([#7874](https://github.com/sveltejs/svelte/issues/7874))
* Omit a11y "no child content" warning on elements with `aria-label` ([#8299](https://github.com/sveltejs/svelte/pull/8299)) * Omit a11y "no child content" warning on elements with `aria-label` ([#8299](https://github.com/sveltejs/svelte/pull/8299))
* Omit a11y warnings on `<svelte:element>` ([#7939](https://github.com/sveltejs/svelte/issues/7939))
* Make `noreferrer` warning less zealous ([#6289](https://github.com/sveltejs/svelte/issues/6289)) * Make `noreferrer` warning less zealous ([#6289](https://github.com/sveltejs/svelte/issues/6289))
* `trusted-types` CSP compatibility for Web Components ([#8134](https://github.com/sveltejs/svelte/issues/8134)) * `trusted-types` CSP compatibility for Web Components ([#8134](https://github.com/sveltejs/svelte/issues/8134))
* Add `data-sveltekit-replacestate` and `data-sveltekit-keepfocus` attribute typings ([#8281](https://github.com/sveltejs/svelte/issues/8281)) * Add `data-sveltekit-replacestate` and `data-sveltekit-keepfocus` attribute typings ([#8281](https://github.com/sveltejs/svelte/issues/8281))
@ -19,6 +20,25 @@
* Add `readonly` method to convert `writable` store to readonly ([#6518](https://github.com/sveltejs/svelte/pull/6518)) * Add `readonly` method to convert `writable` store to readonly ([#6518](https://github.com/sveltejs/svelte/pull/6518))
* Ensure `bind:offsetHeight` updates initially ([#4233](https://github.com/sveltejs/svelte/issues/4233)) * Ensure `bind:offsetHeight` updates initially ([#4233](https://github.com/sveltejs/svelte/issues/4233))
* Better handling of `inert` attribute ([#7500](https://github.com/sveltejs/svelte/issues/7500)) * Better handling of `inert` attribute ([#7500](https://github.com/sveltejs/svelte/issues/7500))
* Clear inputs when `bind:group` to `undefined` ([#8214](https://github.com/sveltejs/svelte/issues/8214))
* Ensure nested arrays can change at the same time ([#8282](https://github.com/sveltejs/svelte/issues/8282))
* Reduce use of template literals in SSR output for better performance ([#7539](https://github.com/sveltejs/svelte/pull/7539))
* Allow assigning to property of const while destructuring ([#7964](https://github.com/sveltejs/svelte/issues/7964))
* Don't set selected options if value is unbound or not passed ([#5644](https://github.com/sveltejs/svelte/issues/5644))
* Ensure `<input>` value persists when swapping elements with spread attributes in an `#each` block ([#7578](https://github.com/sveltejs/svelte/issues/7578))
* Select first enabled option by default when initial value is undefined ([#7041](https://github.com/sveltejs/svelte/issues/7041))
* Fix race condition on `svelte:element` with transitions ([#7948](https://github.com/sveltejs/svelte/issues/7948))
* Optimise `<svelte:element>` output code for static tag and static attribute ([#8161](https://github.com/sveltejs/svelte/pull/8161))
* Decode html entities correctly ([#8026](https://github.com/sveltejs/svelte/issues/8026))
* Handle `{@html}` tags inside `<template>` tags ([#7364](https://github.com/sveltejs/svelte/pull/7364))
* Introduce parameter to allow for horizontal slide transition ([#6182](https://github.com/sveltejs/svelte/issues/6182))
* Add `naturalWidth` and `naturalHeight` bindings ([#7771](https://github.com/sveltejs/svelte/issues/7771))
* make `<!-- svelte-ignore ... -->` work above components ([#8082](https://github.com/sveltejs/svelte/issues/8082))
* add global compound selector validation ([#6272](https://github.com/sveltejs/svelte/issues/6272))
* add `stopImmediatePropagation` event modifier ([#5085](https://github.com/sveltejs/svelte/issues/5085))
* add `readyState` binding for media elements ([#6666](https://github.com/sveltejs/svelte/issues/6666))
* call `<svelte:component>` update to `this` only when it's dirty ([#4129](https://github.com/sveltejs/svelte/issues/4129))
* support exclusively special characters in component filenames ([#7143](https://github.com/sveltejs/svelte/issues/7143))
## 3.55.1 ## 3.55.1

@ -707,6 +707,9 @@ export interface HTMLImgAttributes extends HTMLAttributes<HTMLImageElement> {
srcset?: string | undefined | null; srcset?: string | undefined | null;
usemap?: string | undefined | null; usemap?: string | undefined | null;
width?: number | string | undefined | null; width?: number | string | undefined | null;
readonly 'bind:naturalWidth'?: number | undefined | null;
readonly 'bind:naturalHeight'?: number | undefined | null;
} }
export interface HTMLInsAttributes extends HTMLAttributes<HTMLModElement> { export interface HTMLInsAttributes extends HTMLAttributes<HTMLModElement> {
@ -842,6 +845,7 @@ export interface HTMLMediaAttributes<T extends HTMLMediaElement> extends HTMLAtt
*/ */
volume?: number | undefined | null; volume?: number | undefined | null;
readonly 'bind:readyState'?: 0 | 1 | 2 | 3 | 4 | undefined | null;
readonly 'bind:duration'?: number | undefined | null; readonly 'bind:duration'?: number | undefined | null;
readonly 'bind:buffered'?: SvelteMediaTimeRange[] | undefined | null; readonly 'bind:buffered'?: SvelteMediaTimeRange[] | undefined | null;
readonly 'bind:played'?: SvelteMediaTimeRange[] | undefined | null; readonly 'bind:played'?: SvelteMediaTimeRange[] | undefined | null;

@ -539,6 +539,7 @@ The following modifiers are available:
* `preventDefault` — calls `event.preventDefault()` before running the handler * `preventDefault` — calls `event.preventDefault()` before running the handler
* `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element * `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
* `stopImmediatePropagation` - calls `event.stopImmediatePropagation()`, preventing other listeners of the same event from being fired.
* `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so) * `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
* `nonpassive` — explicitly set `passive: false` * `nonpassive` — explicitly set `passive: false`
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
@ -713,7 +714,7 @@ Elements with the `contenteditable` attribute support `innerHTML` and `textConte
--- ---
Media elements (`<audio>` and `<video>`) have their own set of bindings — six *readonly* ones... Media elements (`<audio>` and `<video>`) have their own set of bindings — seven *readonly* ones...
* `duration` (readonly) — the total duration of the video, in seconds * `duration` (readonly) — the total duration of the video, in seconds
* `buffered` (readonly) — an array of `{start, end}` objects * `buffered` (readonly) — an array of `{start, end}` objects
@ -721,6 +722,7 @@ Media elements (`<audio>` and `<video>`) have their own set of bindings — six
* `seekable` (readonly) — ditto * `seekable` (readonly) — ditto
* `seeking` (readonly) — boolean * `seeking` (readonly) — boolean
* `ended` (readonly) — boolean * `ended` (readonly) — boolean
* `readyState` (readonly) — number between (and including) 0 and 4
...and five *two-way* bindings: ...and five *two-way* bindings:
@ -741,6 +743,7 @@ Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
bind:seekable bind:seekable
bind:seeking bind:seeking
bind:ended bind:ended
bind:readyState
bind:currentTime bind:currentTime
bind:playbackRate bind:playbackRate
bind:paused bind:paused

@ -768,6 +768,7 @@ Slides an element in and out.
* `delay` (`number`, default 0) — milliseconds before starting * `delay` (`number`, default 0) — milliseconds before starting
* `duration` (`number`, default 400) — milliseconds the transition lasts * `duration` (`number`, default 400) — milliseconds the transition lasts
* `easing` (`function`, default `cubicOut`) — an [easing function](/docs#run-time-svelte-easing) * `easing` (`function`, default `cubicOut`) — an [easing function](/docs#run-time-svelte-easing)
- `axis` (`x` | `y`, default `y`) — the axis of motion along which the transition occurs
```sv ```sv
<script> <script>
@ -776,8 +777,8 @@ Slides an element in and out.
</script> </script>
{#if condition} {#if condition}
<div transition:slide="{{delay: 250, duration: 300, easing: quintOut }}"> <div transition:slide="{{delay: 250, duration: 300, easing: quintOut, axis: 'x'}}">
slides in and out slides in and out horizontally
</div> </div>
{/if} {/if}
``` ```

@ -4,7 +4,7 @@ title: Keyed each blocks
By default, when you modify the value of an `each` block, it will add and remove items at the *end* of the block, and update any values that have changed. That might not be what you want. By default, when you modify the value of an `each` block, it will add and remove items at the *end* of the block, and update any values that have changed. That might not be what you want.
It's easier to show why than to explain. Click the 'Remove first thing' button a few times, and notice what happens: it does not remove the first `<Thing>` component, but rather the *last* DOM node. Then it updates the `name` value in the remaining DOM nodes, but not the emoji. It's easier to show why than to explain. Click to expand the `Console`, then click the 'Remove first thing' button a few times, and notice what happens: it does not remove the first `<Thing>` component, but rather the *last* DOM node. Then it updates the `name` value in the remaining DOM nodes, but not the emoji.
Instead, we'd like to remove only the first `<Thing>` component and its DOM node, and leave the others unaffected. Instead, we'd like to remove only the first `<Thing>` component and its DOM node, and leave the others unaffected.

@ -234,6 +234,10 @@ export default {
code: 'css-invalid-global-selector', code: 'css-invalid-global-selector',
message: ':global(...) must contain a single selector' message: ':global(...) must contain a single selector'
}, },
css_invalid_global_selector_position: {
code: 'css-invalid-global-selector-position',
message: ':global(...) not at the start of a selector sequence should not contain type or universal selectors'
},
css_invalid_selector: (selector: string) => ({ css_invalid_selector: (selector: string) => ({
code: 'css-invalid-selector', code: 'css-invalid-selector',
message: `Invalid selector "${selector}"` message: `Invalid selector "${selector}"`

@ -190,10 +190,10 @@ export default {
code: 'a11y-mouse-events-have-key-events', code: 'a11y-mouse-events-have-key-events',
message: `A11y: on:${event} must be accompanied by on:${accompanied_by}` message: `A11y: on:${event} must be accompanied by on:${accompanied_by}`
}), }),
a11y_click_events_have_key_events: () => ({ a11y_click_events_have_key_events: {
code: 'a11y-click-events-have-key-events', code: 'a11y-click-events-have-key-events',
message: 'A11y: visible, non-interactive elements with an on:click event must be accompanied by an on:keydown, on:keyup, or on:keypress event.' message: 'A11y: visible, non-interactive elements with an on:click event must be accompanied by an on:keydown, on:keyup, or on:keypress event.'
}), },
a11y_missing_content: (name: string) => ({ a11y_missing_content: (name: string) => ({
code: 'a11y-missing-content', code: 'a11y-missing-content',
message: `A11y: <${name}> element should have child content` message: `A11y: <${name}> element should have child content`

@ -148,6 +148,7 @@ export default class Selector {
} }
this.validate_global_with_multiple_selectors(component); this.validate_global_with_multiple_selectors(component);
this.validate_global_compound_selector(component);
this.validate_invalid_combinator_without_selector(component); this.validate_invalid_combinator_without_selector(component);
} }
@ -179,6 +180,23 @@ export default class Selector {
} }
} }
validate_global_compound_selector(component: Component) {
for (const block of this.blocks) {
for (let index = 0; index < block.selectors.length; index++) {
const selector = block.selectors[index];
if (selector.type === 'PseudoClassSelector' &&
selector.name === 'global' &&
index !== 0 &&
selector.children &&
selector.children.length > 0 &&
!/[.:#\s]/.test(selector.children[0].value)
) {
component.error(selector, compiler_errors.css_invalid_global_selector_position);
}
}
}
}
get_amount_class_specificity_increased() { get_amount_class_specificity_increased() {
let count = 0; let count = 0;
for (const block of this.blocks) { for (const block of this.blocks) {

@ -24,7 +24,8 @@ const read_only_media_attributes = new Set([
'videoHeight', 'videoHeight',
'videoWidth', 'videoWidth',
'naturalWidth', 'naturalWidth',
'naturalHeight' 'naturalHeight',
'readyState'
]); ]);
export default class Binding extends Node { export default class Binding extends Node {

@ -182,6 +182,7 @@ const invisible_elements = new Set(['meta', 'html', 'script', 'style']);
const valid_modifiers = new Set([ const valid_modifiers = new Set([
'preventDefault', 'preventDefault',
'stopPropagation', 'stopPropagation',
'stopImmediatePropagation',
'capture', 'capture',
'once', 'once',
'passive', 'passive',
@ -549,7 +550,7 @@ export default class Element extends Node {
} }
// aria-activedescendant-has-tabindex // aria-activedescendant-has-tabindex
if (name === 'aria-activedescendant' && !is_interactive_element(this.name, attribute_map) && !attribute_map.has('tabindex')) { if (name === 'aria-activedescendant' && !this.is_dynamic_element && !is_interactive_element(this.name, attribute_map) && !attribute_map.has('tabindex')) {
component.warn(attribute, compiler_warnings.a11y_aria_activedescendant_has_tabindex); component.warn(attribute, compiler_warnings.a11y_aria_activedescendant_has_tabindex);
} }
} }
@ -589,7 +590,7 @@ export default class Element extends Node {
} }
// role-has-required-aria-props // role-has-required-aria-props
if (!is_semantic_role_element(current_role, this.name, attribute_map)) { if (!this.is_dynamic_element && !is_semantic_role_element(current_role, this.name, attribute_map)) {
const role = roles.get(current_role); const role = roles.get(current_role);
if (role) { if (role) {
const required_role_props = Object.keys(role.requiredProps); const required_role_props = Object.keys(role.requiredProps);
@ -625,7 +626,7 @@ export default class Element extends Node {
} }
// scope // scope
if (name === 'scope' && this.name !== 'th') { if (name === 'scope' && !this.is_dynamic_element && this.name !== 'th') {
component.warn(attribute, compiler_warnings.a11y_misplaced_scope); component.warn(attribute, compiler_warnings.a11y_misplaced_scope);
} }
@ -645,6 +646,7 @@ export default class Element extends Node {
const is_non_presentation_role = role?.is_static && !is_presentation_role(role.get_static_value() as ARIARoleDefintionKey); const is_non_presentation_role = role?.is_static && !is_presentation_role(role.get_static_value() as ARIARoleDefintionKey);
if ( if (
!this.is_dynamic_element &&
!is_hidden_from_screen_reader(this.name, attribute_map) && !is_hidden_from_screen_reader(this.name, attribute_map) &&
(!role || is_non_presentation_role) && (!role || is_non_presentation_role) &&
!is_interactive_element(this.name, attribute_map) && !is_interactive_element(this.name, attribute_map) &&
@ -658,14 +660,14 @@ export default class Element extends Node {
if (!has_key_event) { if (!has_key_event) {
component.warn( component.warn(
this, this,
compiler_warnings.a11y_click_events_have_key_events() compiler_warnings.a11y_click_events_have_key_events
); );
} }
} }
} }
// no-noninteractive-tabindex // no-noninteractive-tabindex
if (!is_interactive_element(this.name, attribute_map) && !is_interactive_roles(attribute_map.get('role')?.get_static_value() as ARIARoleDefintionKey)) { if (!this.is_dynamic_element && !is_interactive_element(this.name, attribute_map) && !is_interactive_roles(attribute_map.get('role')?.get_static_value() as ARIARoleDefintionKey)) {
const tab_index = attribute_map.get('tabindex'); const tab_index = attribute_map.get('tabindex');
if (tab_index && (!tab_index.is_static || Number(tab_index.get_static_value()) >= 0)) { if (tab_index && (!tab_index.is_static || Number(tab_index.get_static_value()) >= 0)) {
component.warn(this, compiler_warnings.a11y_no_noninteractive_tabindex); component.warn(this, compiler_warnings.a11y_no_noninteractive_tabindex);
@ -981,7 +983,8 @@ export default class Element extends Node {
name === 'muted' || name === 'muted' ||
name === 'playbackRate' || name === 'playbackRate' ||
name === 'seeking' || name === 'seeking' ||
name === 'ended' name === 'ended' ||
name === 'readyState'
) { ) {
if (this.name !== 'audio' && this.name !== 'video') { if (this.name !== 'audio' && this.name !== 'video') {
return component.error(binding, compiler_errors.invalid_binding_element_with('audio> or <video>', name)); return component.error(binding, compiler_errors.invalid_binding_element_with('audio> or <video>', name));

@ -266,7 +266,7 @@ function get_dom_updater(
const type = node.get_static_attribute_value('type'); const type = node.get_static_attribute_value('type');
const condition = type === 'checkbox' const condition = type === 'checkbox'
? x`~${binding.snippet}.indexOf(${element.var}.__value)` ? x`~(${binding.snippet} || []).indexOf(${element.var}.__value)`
: x`${element.var}.__value === ${binding.snippet}`; : x`${element.var}.__value === ${binding.snippet}`;
return b`${element.var}.checked = ${condition};`; return b`${element.var}.checked = ${condition};`;

@ -41,6 +41,7 @@ export default class EventHandlerWrapper {
if (this.node.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`; if (this.node.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`;
if (this.node.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`; if (this.node.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`;
if (this.node.modifiers.has('stopImmediatePropagation')) snippet = x`@stop_immediate_propagation(${snippet})`;
if (this.node.modifiers.has('self')) snippet = x`@self(${snippet})`; if (this.node.modifiers.has('self')) snippet = x`@self(${snippet})`;
if (this.node.modifiers.has('trusted')) snippet = x`@trusted(${snippet})`; if (this.node.modifiers.has('trusted')) snippet = x`@trusted(${snippet})`;
@ -64,6 +65,7 @@ export default class EventHandlerWrapper {
if (block.renderer.options.dev) { if (block.renderer.options.dev) {
args.push(this.node.modifiers.has('preventDefault') ? TRUE : FALSE); args.push(this.node.modifiers.has('preventDefault') ? TRUE : FALSE);
args.push(this.node.modifiers.has('stopPropagation') ? TRUE : FALSE); args.push(this.node.modifiers.has('stopPropagation') ? TRUE : FALSE);
args.push(this.node.modifiers.has('stopImmediatePropagation') ? TRUE : FALSE);
} }
block.event_listeners.push( block.event_listeners.push(

@ -63,13 +63,11 @@ const events = [
filter: (node: Element, _name: string) => filter: (node: Element, _name: string) =>
node.name === 'input' && node.get_static_attribute_value('type') === 'range' node.name === 'input' && node.get_static_attribute_value('type') === 'range'
}, },
{ {
event_names: ['elementresize'], event_names: ['elementresize'],
filter: (_node: Element, name: string) => filter: (_node: Element, name: string) =>
regex_dimensions.test(name) regex_dimensions.test(name)
}, },
// media events // media events
{ {
event_names: ['timeupdate'], event_names: ['timeupdate'],
@ -131,7 +129,14 @@ const events = [
node.is_media_node() && node.is_media_node() &&
(name === 'videoHeight' || name === 'videoWidth') (name === 'videoHeight' || name === 'videoWidth')
}, },
{
// from https://html.spec.whatwg.org/multipage/media.html#ready-states
// and https://html.spec.whatwg.org/multipage/media.html#loading-the-media-resource
event_names: ['loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'emptied'],
filter: (node: Element, name: string) =>
node.is_media_node() &&
name === 'readyState'
},
// details event // details event
{ {
event_names: ['toggle'], event_names: ['toggle'],
@ -155,6 +160,7 @@ export default class ElementWrapper extends Wrapper {
bindings: Binding[]; bindings: Binding[];
event_handlers: EventHandler[]; event_handlers: EventHandler[];
class_dependencies: string[]; class_dependencies: string[];
has_dynamic_attribute: boolean;
select_binding_dependencies?: Set<string>; select_binding_dependencies?: Set<string>;
@ -223,6 +229,7 @@ export default class ElementWrapper extends Wrapper {
} }
return new AttributeWrapper(this, block, attribute); return new AttributeWrapper(this, block, attribute);
}); });
this.has_dynamic_attribute = !!this.attributes.find(attr => attr.node.get_dependencies().length > 0);
// ordinarily, there'll only be one... but we need to handle // ordinarily, there'll only be one... but we need to handle
// the rare case where an element can have multiple bindings, // the rare case where an element can have multiple bindings,
@ -291,9 +298,8 @@ export default class ElementWrapper extends Wrapper {
(x`#nodes` as unknown) as Identifier (x`#nodes` as unknown) as Identifier
); );
const previous_tag = block.get_unique_name('previous_tag'); const is_tag_dynamic = this.node.tag_expr.dynamic_dependencies().length > 0;
const tag = this.node.tag_expr.manipulate(block); const tag = this.node.tag_expr.manipulate(block);
block.add_variable(previous_tag, tag);
block.chunks.init.push(b` block.chunks.init.push(b`
${this.renderer.options.dev && b`@validate_dynamic_element(${tag});`} ${this.renderer.options.dev && b`@validate_dynamic_element(${tag});`}
@ -315,6 +321,9 @@ export default class ElementWrapper extends Wrapper {
if (${this.var}) ${this.var}.m(${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'}); if (${this.var}) ${this.var}.m(${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});
`); `);
if (is_tag_dynamic) {
const previous_tag = block.get_unique_name('previous_tag');
block.add_variable(previous_tag, tag);
const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes); const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
const has_transitions = !!(this.node.intro || this.node.outro); const has_transitions = !!(this.node.intro || this.node.outro);
const not_equal = this.renderer.component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; const not_equal = this.renderer.component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`;
@ -371,6 +380,13 @@ export default class ElementWrapper extends Wrapper {
} }
} }
`); `);
} else {
block.chunks.update.push(b`
if (${tag}) {
${this.var}.p(#ctx, #dirty);
}
`);
}
if (this.child_dynamic_element_block.has_intros) { if (this.child_dynamic_element_block.has_intros) {
block.chunks.intro.push(b`@transition_in(${this.var});`); block.chunks.intro.push(b`@transition_in(${this.var});`);
@ -509,7 +525,11 @@ export default class ElementWrapper extends Wrapper {
block.maintain_context = true; block.maintain_context = true;
} }
if (this.node.is_dynamic_element) {
this.add_dynamic_element_attributes(block);
} else {
this.add_attributes(block); this.add_attributes(block);
}
this.add_directives_in_order(block); this.add_directives_in_order(block);
this.add_transitions(block); this.add_transitions(block);
this.add_animation(block); this.add_animation(block);
@ -787,7 +807,7 @@ export default class ElementWrapper extends Wrapper {
} }
}); });
if (this.node.attributes.some(attr => attr.is_spread) || this.node.is_dynamic_element) { if (this.node.attributes.some(attr => attr.is_spread)) {
this.add_spread_attributes(block); this.add_spread_attributes(block);
return; return;
} }
@ -836,29 +856,18 @@ export default class ElementWrapper extends Wrapper {
} }
`); `);
const fn = this.node.namespace === namespaces.svg ? x`@set_svg_attributes` : x`@set_attributes`; const fn =
this.node.namespace === namespaces.svg
? x`@set_svg_attributes`
: this.node.is_dynamic_element
? x`@set_dynamic_element_data(${this.node.tag_expr.manipulate(block)})`
: x`@set_attributes`;
if (this.node.is_dynamic_element) {
// call attribute bindings for custom element if tag is custom element
const tag = this.node.tag_expr.manipulate(block);
const attr_update = this.node.namespace === namespaces.svg
? b`${fn}(${this.var}, ${data});`
: b`
if (/-/.test(${tag})) {
@set_custom_element_data_map(${this.var}, ${data});
} else {
${fn}(${this.var}, ${data});
}`;
block.chunks.hydrate.push(attr_update);
block.chunks.update.push(b`
${data} = @get_spread_update(${levels}, [${updates}]);
${attr_update}`
);
} else {
block.chunks.hydrate.push( block.chunks.hydrate.push(
b`${fn}(${this.var}, ${data});` b`${fn}(${this.var}, ${data});`
); );
if (this.has_dynamic_attribute) {
block.chunks.update.push(b` block.chunks.update.push(b`
${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [ ${fn}(${this.var}, ${data} = @get_spread_update(${levels}, [
${updates} ${updates}
@ -905,6 +914,35 @@ export default class ElementWrapper extends Wrapper {
} }
} }
add_dynamic_element_attributes(block: Block) {
if (this.attributes.length === 0) return;
if (this.has_dynamic_attribute) {
this.add_spread_attributes(block);
return;
}
const static_attributes = [];
this.attributes.forEach((attr) => {
if (attr instanceof SpreadAttributeWrapper) {
static_attributes.push({ type: 'SpreadElement', argument: attr.node.expression.node });
} else {
const name = attr.property_name || attr.name;
static_attributes.push(p`${name}: ${attr.get_value(block)}`);
}
});
const fn =
this.node.namespace === namespaces.svg
? x`@set_svg_attributes`
: this.node.is_dynamic_element
? x`@set_dynamic_element_data(${this.node.tag_expr.manipulate(block)})`
: x`@set_attributes`;
block.chunks.hydrate.push(
b`${fn}(${this.var}, {${static_attributes}});`
);
}
add_transitions(block: Block) { add_transitions(block: Block) {
const { intro, outro } = this.node; const { intro, outro } = this.node;
if (!intro && !outro) return; if (!intro && !outro) return;
@ -1102,7 +1140,7 @@ export default class ElementWrapper extends Wrapper {
block.chunks.hydrate.push(updater); block.chunks.hydrate.push(updater);
if (has_spread || this.node.is_dynamic_element) { if ((this.node.is_dynamic_element || has_spread) && this.has_dynamic_attribute) {
block.chunks.update.push(updater); block.chunks.update.push(updater);
} else if ((dependencies && dependencies.size > 0) || this.class_dependencies.length) { } else if ((dependencies && dependencies.size > 0) || this.class_dependencies.length) {
const all_dependencies = this.class_dependencies.concat(...dependencies); const all_dependencies = this.class_dependencies.concat(...dependencies);

@ -21,6 +21,7 @@ import SlotTemplate from '../../../nodes/SlotTemplate';
import { is_head } from '../shared/is_head'; import { is_head } from '../shared/is_head';
import compiler_warnings from '../../../compiler_warnings'; import compiler_warnings from '../../../compiler_warnings';
import { namespaces } from '../../../../utils/namespaces'; import { namespaces } from '../../../../utils/namespaces';
import { extract_ignores_above_node } from '../../../../utils/extract_svelte_ignore';
type SlotDefinition = { block: Block; scope: TemplateScope; get_context?: Node; get_changes?: Node }; type SlotDefinition = { block: Block; scope: TemplateScope; get_context?: Node; get_changes?: Node };
@ -111,9 +112,12 @@ export default class InlineComponentWrapper extends Wrapper {
return; return;
} }
const ignores = extract_ignores_above_node(this.node);
this.renderer.component.push_ignores(ignores);
if (variable.reassigned || variable.export_name || variable.is_reactive_dependency) { if (variable.reassigned || variable.export_name || variable.is_reactive_dependency) {
this.renderer.component.warn(this.node, compiler_warnings.reactive_component(name)); this.renderer.component.warn(this.node, compiler_warnings.reactive_component(name));
} }
this.renderer.component.pop_ignores();
} }
render( render(

@ -16,6 +16,7 @@ import Title from './handlers/Title';
import { AppendTarget, CompileOptions } from '../../interfaces'; import { AppendTarget, CompileOptions } from '../../interfaces';
import { INode } from '../nodes/interfaces'; import { INode } from '../nodes/interfaces';
import { Expression, TemplateLiteral, Identifier } from 'estree'; import { Expression, TemplateLiteral, Identifier } from 'estree';
import { collapse_template_literal } from '../utils/collapse_template_literal';
import { escape_template } from '../utils/stringify'; import { escape_template } from '../utils/stringify';
type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void;
@ -106,6 +107,9 @@ export default class Renderer {
this.current = last.current; this.current = last.current;
} }
// Optimize the TemplateLiteral to remove unnecessary nodes
collapse_template_literal(popped.literal);
return popped.literal; return popped.literal;
} }

@ -13,4 +13,10 @@ describe('get_name_from_filename', () => {
it('handles Windows filenames', () => { it('handles Windows filenames', () => {
assert.equal(get_name_from_filename('path\\to\\Widget.svelte'), 'Widget'); assert.equal(get_name_from_filename('path\\to\\Widget.svelte'), 'Widget');
}); });
it('handles special characters in filenames', () => {
assert.equal(get_name_from_filename('@.svelte'), '_');
assert.equal(get_name_from_filename('&.svelte'), '_');
assert.equal(get_name_from_filename('~.svelte'), '_');
});
}); });

@ -0,0 +1,34 @@
import { TemplateLiteral } from 'estree';
import { escape_template } from './stringify';
/**
* Collapse string literals together
*/
export function collapse_template_literal(literal: TemplateLiteral) {
if (!literal.quasis.length) return;
const collapsed_quasis = [];
const collapsed_expressions = [];
let cur_quasi = literal.quasis[0];
// An expression always follows a quasi and vice versa, ending with a quasi
for (let i = 0; i < literal.quasis.length; i++) {
const expr = literal.expressions[i];
const next_quasi = literal.quasis[i + 1];
// If an expression is a simple string literal, combine it with its preceding
// and following quasi
if (next_quasi && expr && expr.type === 'Literal' && typeof expr.value === 'string') {
cur_quasi.value.raw += escape_template(expr.value) + next_quasi.value.raw;
} else {
if (expr) {
collapsed_expressions.push(expr);
}
collapsed_quasis.push(cur_quasi);
cur_quasi = next_quasi;
}
}
literal.quasis = collapsed_quasis;
literal.expressions = collapsed_expressions;
}

@ -1,9 +1,8 @@
import { regex_starts_with_underscore, regex_ends_with_underscore } from '../../utils/patterns';
const regex_percentage_characters = /%/g; const regex_percentage_characters = /%/g;
const regex_file_ending = /\.[^.]+$/; const regex_file_ending = /\.[^.]+$/;
const regex_repeated_invalid_variable_identifier_characters = /[^a-zA-Z_$0-9]+/g; const regex_repeated_invalid_variable_identifier_characters = /[^a-zA-Z_$0-9]+/g;
const regex_starts_with_digit = /^(\d)/; const regex_starts_with_digit = /^(\d)/;
const regex_may_starts_or_ends_with_underscore = /^_?(.+?)_?$/;
export default function get_name_from_filename(filename: string) { export default function get_name_from_filename(filename: string) {
if (!filename) return null; if (!filename) return null;
@ -18,12 +17,12 @@ export default function get_name_from_filename(filename: string) {
} }
} }
const base = parts.pop() const base = parts
.pop()
.replace(regex_percentage_characters, 'u') .replace(regex_percentage_characters, 'u')
.replace(regex_file_ending, '') .replace(regex_file_ending, '')
.replace(regex_repeated_invalid_variable_identifier_characters, '_') .replace(regex_repeated_invalid_variable_identifier_characters, '_')
.replace(regex_starts_with_underscore, '') .replace(regex_may_starts_or_ends_with_underscore, '$1')
.replace(regex_ends_with_underscore, '')
.replace(regex_starts_with_digit, '_$1'); .replace(regex_starts_with_digit, '_$1');
if (!base) { if (!base) {

@ -519,7 +519,7 @@ function read_sequence(parser: Parser, done: () => boolean, location: string): T
function flush(end: number) { function flush(end: number) {
if (current_chunk.raw) { if (current_chunk.raw) {
current_chunk.data = decode_character_references(current_chunk.raw); current_chunk.data = decode_character_references(current_chunk.raw, true);
current_chunk.end = end; current_chunk.end = end;
chunks.push(current_chunk); chunks.push(current_chunk);
} }

@ -19,7 +19,7 @@ export default function text(parser: Parser) {
end: parser.index, end: parser.index,
type: 'Text', type: 'Text',
raw: data, raw: data,
data: decode_character_references(data) data: decode_character_references(data, false)
}; };
parser.current().children.push(node); parser.current().children.push(node);

File diff suppressed because it is too large Load Diff

@ -35,12 +35,32 @@ const windows_1252 = [
376 376
]; ];
function reg_exp_entity(entity_name: string, is_attribute_value: boolean) {
// https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
// doesn't decode the html entity which not ends with ; and next character is =, number or alphabet in attribute value.
if (is_attribute_value && !entity_name.endsWith(';')) {
return `${entity_name}\\b(?!=)`;
}
return entity_name;
}
function get_entity_pattern(is_attribute_value: boolean) {
const reg_exp_num = '#(?:x[a-fA-F\\d]+|\\d+)(?:;)?';
const reg_exp_entities = Object.keys(entities).map(entity_name => reg_exp_entity(entity_name, is_attribute_value));
const entity_pattern = new RegExp( const entity_pattern = new RegExp(
`&(#?(?:x[\\w\\d]+|\\d+|${Object.keys(entities).join('|')}))(?:;|\\b)`, `&(${reg_exp_num}|${reg_exp_entities.join('|')})`,
'g' 'g'
); );
export function decode_character_references(html: string) { return entity_pattern;
}
const entity_pattern_content = get_entity_pattern(false);
const entity_pattern_attr_value = get_entity_pattern(true);
export function decode_character_references(html: string, is_attribute_value: boolean) {
const entity_pattern = is_attribute_value ? entity_pattern_attr_value : entity_pattern_content;
return html.replace(entity_pattern, (match, entity) => { return html.replace(entity_pattern, (match, entity) => {
let code; let code;

@ -1,6 +1,7 @@
import { TemplateNode } from '../interfaces'; import { TemplateNode } from '../interfaces';
import { flatten } from './flatten'; import { flatten } from './flatten';
import { regex_whitespace } from './patterns'; import { regex_whitespace } from './patterns';
import { INode } from '../compile/nodes/interfaces';
const regex_svelte_ignore = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m; const regex_svelte_ignore = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m;
@ -33,3 +34,25 @@ export function extract_ignores_above_position(position: number, template_nodes:
return []; return [];
} }
export function extract_ignores_above_node(node: INode): string[] {
/**
* This utilizes the fact that node has a prev and a next attribute
* which means that it can find svelte-ignores along
* the nodes on the same level as itself who share the same parent.
*/
let cur_node = node.prev;
while (cur_node) {
if (cur_node.type !== 'Comment' && cur_node.type !== 'Text') {
return [];
}
if (cur_node.type === 'Comment' && cur_node.ignores.length) {
return cur_node.ignores;
}
cur_node = cur_node.prev;
}
return [];
}

@ -49,10 +49,11 @@ export function detach_after_dev(before: Node) {
} }
} }
export function listen_dev(node: Node, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions, has_prevent_default?: boolean, has_stop_propagation?: boolean) { export function listen_dev(node: Node, event: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | EventListenerOptions, has_prevent_default?: boolean, has_stop_propagation?: boolean, has_stop_immediate_propagation?: boolean) {
const modifiers = options === true ? [ 'capture' ] : options ? Array.from(Object.keys(options)) : []; const modifiers = options === true ? [ 'capture' ] : options ? Array.from(Object.keys(options)) : [];
if (has_prevent_default) modifiers.push('preventDefault'); if (has_prevent_default) modifiers.push('preventDefault');
if (has_stop_propagation) modifiers.push('stopPropagation'); if (has_stop_propagation) modifiers.push('stopPropagation');
if (has_stop_immediate_propagation) modifiers.push('stopImmediatePropagation');
dispatch_dev('SvelteDOMAddEventListener', { node, event, handler, modifiers }); dispatch_dev('SvelteDOMAddEventListener', { node, event, handler, modifiers });

@ -275,6 +275,14 @@ export function stop_propagation(fn) {
}; };
} }
export function stop_immediate_propagation(fn) {
return function (event) {
event.stopImmediatePropagation();
// @ts-ignore
return fn.call(this, event);
};
}
export function self(fn) { export function self(fn) {
return function(event) { return function(event) {
// @ts-ignore // @ts-ignore
@ -332,6 +340,10 @@ export function set_custom_element_data(node, prop, value) {
} }
} }
export function set_dynamic_element_data(tag: string) {
return (/-/.test(tag)) ? set_custom_element_data_map : set_attributes;
}
export function xlink_attr(node, attribute, value) { export function xlink_attr(node, attribute, value) {
node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value); node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value);
} }
@ -694,7 +706,7 @@ export class HtmlTag {
// html tag nodes // html tag nodes
n: ChildNode[]; n: ChildNode[];
// target // target
t: HTMLElement | SVGElement; t: HTMLElement | SVGElement | DocumentFragment;
// anchor // anchor
a: HTMLElement | SVGElement; a: HTMLElement | SVGElement;
@ -714,8 +726,9 @@ export class HtmlTag {
) { ) {
if (!this.e) { if (!this.e) {
if (this.is_svg) this.e = svg_element(target.nodeName as keyof SVGElementTagNameMap); if (this.is_svg) this.e = svg_element(target.nodeName as keyof SVGElementTagNameMap);
else this.e = element(target.nodeName as keyof HTMLElementTagNameMap); /** #7364 target for <template> may be provided as #document-fragment(11) */
this.t = target; else this.e = element((target.nodeType === 11 ? 'TEMPLATE' : target.nodeName) as keyof HTMLElementTagNameMap);
this.t = target.tagName !== 'TEMPLATE' ? target : (target as HTMLTemplateElement).content;
this.c(html); this.c(html);
} }
@ -724,7 +737,7 @@ export class HtmlTag {
h(html: string) { h(html: string) {
this.e.innerHTML = html; this.e.innerHTML = html;
this.n = Array.from(this.e.childNodes); this.n = Array.from(this.e.nodeName === 'TEMPLATE' ? (this.e as HTMLTemplateElement).content.childNodes : this.e.childNodes);
} }
i(anchor) { i(anchor) {

@ -98,23 +98,27 @@ export interface SlideParams {
delay?: number; delay?: number;
duration?: number; duration?: number;
easing?: EasingFunction; easing?: EasingFunction;
axis?: 'x' | 'y';
} }
export function slide(node: Element, { export function slide(node: Element, {
delay = 0, delay = 0,
duration = 400, duration = 400,
easing = cubicOut easing = cubicOut,
axis = 'y'
}: SlideParams = {}): TransitionConfig { }: SlideParams = {}): TransitionConfig {
const style = getComputedStyle(node); const style = getComputedStyle(node);
const opacity = +style.opacity; const opacity = +style.opacity;
const height = parseFloat(style.height); const primary_property = axis === 'y' ? 'height' : 'width';
const padding_top = parseFloat(style.paddingTop); const primary_property_value = parseFloat(style[primary_property]);
const padding_bottom = parseFloat(style.paddingBottom); const secondary_properties = axis === 'y' ? ['top', 'bottom'] : ['left', 'right'];
const margin_top = parseFloat(style.marginTop); const capitalized_secondary_properties = secondary_properties.map((e) => `${e[0].toUpperCase()}${e.slice(1)}`);
const margin_bottom = parseFloat(style.marginBottom); const padding_start_value = parseFloat(style[`padding${capitalized_secondary_properties[0]}`]);
const border_top_width = parseFloat(style.borderTopWidth); const padding_end_value = parseFloat(style[`padding${capitalized_secondary_properties[1]}`]);
const border_bottom_width = parseFloat(style.borderBottomWidth); const margin_start_value = parseFloat(style[`margin${capitalized_secondary_properties[0]}`]);
const margin_end_value = parseFloat(style[`margin${capitalized_secondary_properties[1]}`]);
const border_width_start_value = parseFloat(style[`border${capitalized_secondary_properties[0]}Width`]);
const border_width_end_value = parseFloat(style[`border${capitalized_secondary_properties[1]}Width`]);
return { return {
delay, delay,
duration, duration,
@ -122,13 +126,13 @@ export function slide(node: Element, {
css: t => css: t =>
'overflow: hidden;' + 'overflow: hidden;' +
`opacity: ${Math.min(t * 20, 1) * opacity};` + `opacity: ${Math.min(t * 20, 1) * opacity};` +
`height: ${t * height}px;` + `${primary_property}: ${t * primary_property_value}px;` +
`padding-top: ${t * padding_top}px;` + `padding-${secondary_properties[0]}: ${t * padding_start_value}px;` +
`padding-bottom: ${t * padding_bottom}px;` + `padding-${secondary_properties[1]}: ${t * padding_end_value}px;` +
`margin-top: ${t * margin_top}px;` + `margin-${secondary_properties[0]}: ${t * margin_start_value}px;` +
`margin-bottom: ${t * margin_bottom}px;` + `margin-${secondary_properties[1]}: ${t * margin_end_value}px;` +
`border-top-width: ${t * border_top_width}px;` + `border-${secondary_properties[0]}-width: ${t * border_width_start_value}px;` +
`border-bottom-width: ${t * border_bottom_width}px;` `border-${secondary_properties[1]}-width: ${t * border_width_end_value}px;`
}; };
} }

@ -0,0 +1,6 @@
export default {
options: {
generate: 'ssr',
dev: true
}
};

@ -0,0 +1,25 @@
/* generated by Svelte vX.Y.Z */
import { add_attribute, create_ssr_component, escape } from "svelte/internal";
const const1 = 1;
const const2 = 'const2';
function foo() {
return '';
}
const Component = create_ssr_component(($$result, $$props, $$bindings, slots) => {
return `
<div class="class1 class2" style="color:red;">-</div>
<div${add_attribute("class", const1, 0)}>-</div>
<div${add_attribute("class", const1, 0)}>-</div>
<div class="${"class1 " + escape('class2', true)}">-</div>
<div class="${"class1 " + escape(const2, true)}">-</div>
<div class="${"class1 " + escape(const2, true)}"${add_attribute("style", foo(), 0)}>-</div>`;
});
export default Component;

@ -0,0 +1,20 @@
<script>
const const1 = 1;
const const2 = 'const2';
function foo() {
return '';
}
</script>
<!-- canonical case - only markup -->
<div class="class1 class2" style="color:red;">-</div>
<!-- various forms of variable syntax -->
<div class="{const1}">-</div>
<div class={const1}>-</div>
<!-- mixed static string + expressions -->
<div class="class1 {'class2'}">-</div>
<div class="class1 {const2}">-</div>
<div class="class1 {const2}" style={foo()}>-</div>

@ -12,6 +12,7 @@ import {
run_all, run_all,
safe_not_equal, safe_not_equal,
space, space,
stop_immediate_propagation,
stop_propagation stop_propagation
} from "svelte/internal"; } from "svelte/internal";
@ -24,6 +25,8 @@ function create_fragment(ctx) {
let button1; let button1;
let t5; let t5;
let button2; let button2;
let t7;
let button3;
let mounted; let mounted;
let dispose; let dispose;
@ -41,6 +44,9 @@ function create_fragment(ctx) {
t5 = space(); t5 = space();
button2 = element("button"); button2 = element("button");
button2.textContent = "or me!"; button2.textContent = "or me!";
t7 = space();
button3 = element("button");
button3.textContent = "or me!";
}, },
m(target, anchor) { m(target, anchor) {
insert(target, div1, anchor); insert(target, div1, anchor);
@ -51,6 +57,8 @@ function create_fragment(ctx) {
append(div1, button1); append(div1, button1);
append(div1, t5); append(div1, t5);
append(div1, button2); append(div1, button2);
append(div1, t7);
append(div1, button3);
if (!mounted) { if (!mounted) {
dispose = [ dispose = [
@ -58,6 +66,8 @@ function create_fragment(ctx) {
listen(button0, "click", stop_propagation(prevent_default(handleClick))), listen(button0, "click", stop_propagation(prevent_default(handleClick))),
listen(button1, "click", handleClick, { once: true, capture: true }), listen(button1, "click", handleClick, { once: true, capture: true }),
listen(button2, "click", handleClick, true), listen(button2, "click", handleClick, true),
listen(button3, "click", stop_immediate_propagation(handleClick)),
listen(button3, "click", handleTouchstart),
listen(div1, "touchstart", handleTouchstart, { passive: true }) listen(div1, "touchstart", handleTouchstart, { passive: true })
]; ];

@ -13,4 +13,9 @@
<button on:click|stopPropagation|preventDefault={handleClick}>click me</button> <button on:click|stopPropagation|preventDefault={handleClick}>click me</button>
<button on:click|once|capture={handleClick}>or me</button> <button on:click|once|capture={handleClick}>or me</button>
<button on:click|capture={handleClick}>or me!</button> <button on:click|capture={handleClick}>or me!</button>
<button
on:click|stopImmediatePropagation={handleClick}
on:click={handleTouchstart}>
or me!
</button>
</div> </div>

@ -30,18 +30,19 @@ function create_fragment(ctx) {
audio_updating = true; audio_updating = true;
} }
/*audio_timeupdate_handler*/ ctx[13].call(audio); /*audio_timeupdate_handler*/ ctx[14].call(audio);
} }
return { return {
c() { c() {
audio = element("audio"); audio = element("audio");
if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[11].call(audio)); if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[12].call(audio));
if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[12].call(audio)); if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[13].call(audio));
if (/*played*/ ctx[2] === void 0 || /*currentTime*/ ctx[3] === void 0 || /*ended*/ ctx[10] === void 0) add_render_callback(audio_timeupdate_handler); if (/*played*/ ctx[2] === void 0 || /*currentTime*/ ctx[3] === void 0 || /*ended*/ ctx[10] === void 0) add_render_callback(audio_timeupdate_handler);
if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[14].call(audio)); if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[15].call(audio));
if (/*seeking*/ ctx[9] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[18].call(audio)); if (/*seeking*/ ctx[9] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[19].call(audio));
if (/*ended*/ ctx[10] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[19].call(audio)); if (/*ended*/ ctx[10] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[20].call(audio));
if (/*readyState*/ ctx[11] === void 0) add_render_callback(() => /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21].call(audio));
}, },
m(target, anchor) { m(target, anchor) {
insert(target, audio, anchor); insert(target, audio, anchor);
@ -58,17 +59,24 @@ function create_fragment(ctx) {
if (!mounted) { if (!mounted) {
dispose = [ dispose = [
listen(audio, "progress", /*audio_progress_handler*/ ctx[11]), listen(audio, "progress", /*audio_progress_handler*/ ctx[12]),
listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[12]), listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[13]),
listen(audio, "timeupdate", audio_timeupdate_handler), listen(audio, "timeupdate", audio_timeupdate_handler),
listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[14]), listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[15]),
listen(audio, "play", /*audio_play_pause_handler*/ ctx[15]), listen(audio, "play", /*audio_play_pause_handler*/ ctx[16]),
listen(audio, "pause", /*audio_play_pause_handler*/ ctx[15]), listen(audio, "pause", /*audio_play_pause_handler*/ ctx[16]),
listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[16]), listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[17]),
listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[17]), listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[18]),
listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[18]), listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[19]),
listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[18]), listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[19]),
listen(audio, "ended", /*audio_ended_handler*/ ctx[19]) listen(audio, "ended", /*audio_ended_handler*/ ctx[20]),
listen(audio, "loadedmetadata", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "loadeddata", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "canplay", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "canplaythrough", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "playing", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "waiting", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21]),
listen(audio, "emptied", /*audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[21])
]; ];
mounted = true; mounted = true;
@ -119,6 +127,7 @@ function instance($$self, $$props, $$invalidate) {
let { playbackRate } = $$props; let { playbackRate } = $$props;
let { seeking } = $$props; let { seeking } = $$props;
let { ended } = $$props; let { ended } = $$props;
let { readyState } = $$props;
function audio_progress_handler() { function audio_progress_handler() {
buffered = time_ranges_to_array(this.buffered); buffered = time_ranges_to_array(this.buffered);
@ -173,6 +182,11 @@ function instance($$self, $$props, $$invalidate) {
$$invalidate(10, ended); $$invalidate(10, ended);
} }
function audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler() {
readyState = this.readyState;
$$invalidate(11, readyState);
}
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ('buffered' in $$props) $$invalidate(0, buffered = $$props.buffered); if ('buffered' in $$props) $$invalidate(0, buffered = $$props.buffered);
if ('seekable' in $$props) $$invalidate(1, seekable = $$props.seekable); if ('seekable' in $$props) $$invalidate(1, seekable = $$props.seekable);
@ -185,6 +199,7 @@ function instance($$self, $$props, $$invalidate) {
if ('playbackRate' in $$props) $$invalidate(8, playbackRate = $$props.playbackRate); if ('playbackRate' in $$props) $$invalidate(8, playbackRate = $$props.playbackRate);
if ('seeking' in $$props) $$invalidate(9, seeking = $$props.seeking); if ('seeking' in $$props) $$invalidate(9, seeking = $$props.seeking);
if ('ended' in $$props) $$invalidate(10, ended = $$props.ended); if ('ended' in $$props) $$invalidate(10, ended = $$props.ended);
if ('readyState' in $$props) $$invalidate(11, readyState = $$props.readyState);
}; };
return [ return [
@ -199,6 +214,7 @@ function instance($$self, $$props, $$invalidate) {
playbackRate, playbackRate,
seeking, seeking,
ended, ended,
readyState,
audio_progress_handler, audio_progress_handler,
audio_loadedmetadata_handler, audio_loadedmetadata_handler,
audio_timeupdate_handler, audio_timeupdate_handler,
@ -207,7 +223,8 @@ function instance($$self, $$props, $$invalidate) {
audio_volumechange_handler, audio_volumechange_handler,
audio_ratechange_handler, audio_ratechange_handler,
audio_seeking_seeked_handler, audio_seeking_seeked_handler,
audio_ended_handler audio_ended_handler,
audio_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler
]; ];
} }
@ -226,7 +243,8 @@ class Component extends SvelteComponent {
muted: 7, muted: 7,
playbackRate: 8, playbackRate: 8,
seeking: 9, seeking: 9,
ended: 10 ended: 10,
readyState: 11
}); });
} }
} }

@ -10,6 +10,7 @@
export let playbackRate; export let playbackRate;
export let seeking; export let seeking;
export let ended; export let ended;
export let readyState;
</script> </script>
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:muted bind:playbackRate bind:seeking bind:ended/> <audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:muted bind:playbackRate bind:seeking bind:ended bind:readyState/>

@ -2,20 +2,16 @@
import { import {
SvelteComponent, SvelteComponent,
append, append,
assign,
bubble, bubble,
detach, detach,
element, element,
empty,
get_spread_update,
init, init,
insert, insert,
listen, listen,
noop, noop,
run_all, run_all,
safe_not_equal, safe_not_equal,
set_attributes, set_dynamic_element_data
set_custom_element_data_map
} from "svelte/internal"; } from "svelte/internal";
function create_dynamic_element(ctx) { function create_dynamic_element(ctx) {
@ -23,36 +19,13 @@ function create_dynamic_element(ctx) {
let svelte_element0; let svelte_element0;
let mounted; let mounted;
let dispose; let dispose;
let svelte_element0_levels = [{ class: "inner" }];
let svelte_element0_data = {};
for (let i = 0; i < svelte_element0_levels.length; i += 1) {
svelte_element0_data = assign(svelte_element0_data, svelte_element0_levels[i]);
}
let svelte_element1_levels = [{ class: "outer" }];
let svelte_element1_data = {};
for (let i = 0; i < svelte_element1_levels.length; i += 1) {
svelte_element1_data = assign(svelte_element1_data, svelte_element1_levels[i]);
}
return { return {
c() { c() {
svelte_element1 = element(a); svelte_element1 = element(a);
svelte_element0 = element(span); svelte_element0 = element(span);
set_dynamic_element_data(span)(svelte_element0, { class: "inner" });
if ((/-/).test(span)) { set_dynamic_element_data(a)(svelte_element1, { class: "outer" });
set_custom_element_data_map(svelte_element0, svelte_element0_data);
} else {
set_attributes(svelte_element0, svelte_element0_data);
}
if ((/-/).test(a)) {
set_custom_element_data_map(svelte_element1, svelte_element1_data);
} else {
set_attributes(svelte_element1, svelte_element1_data);
}
}, },
m(target, anchor) { m(target, anchor) {
insert(target, svelte_element1, anchor); insert(target, svelte_element1, anchor);
@ -69,23 +42,7 @@ function create_dynamic_element(ctx) {
mounted = true; mounted = true;
} }
}, },
p(ctx, dirty) { p: noop,
svelte_element0_data = get_spread_update(svelte_element0_levels, [{ class: "inner" }]);
if ((/-/).test(span)) {
set_custom_element_data_map(svelte_element0, svelte_element0_data);
} else {
set_attributes(svelte_element0, svelte_element0_data);
}
svelte_element1_data = get_spread_update(svelte_element1_levels, [{ class: "outer" }]);
if ((/-/).test(a)) {
set_custom_element_data_map(svelte_element1, svelte_element1_data);
} else {
set_attributes(svelte_element1, svelte_element1_data);
}
},
d(detaching) { d(detaching) {
if (detaching) detach(svelte_element1); if (detaching) detach(svelte_element1);
mounted = false; mounted = false;
@ -95,45 +52,23 @@ function create_dynamic_element(ctx) {
} }
function create_fragment(ctx) { function create_fragment(ctx) {
let previous_tag = a;
let svelte_element_anchor;
let svelte_element = a && create_dynamic_element(ctx); let svelte_element = a && create_dynamic_element(ctx);
return { return {
c() { c() {
if (svelte_element) svelte_element.c(); if (svelte_element) svelte_element.c();
svelte_element_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {
if (svelte_element) svelte_element.m(target, anchor); if (svelte_element) svelte_element.m(target, anchor);
insert(target, svelte_element_anchor, anchor);
}, },
p(ctx, [dirty]) { p(ctx, [dirty]) {
if (a) { if (a) {
if (!previous_tag) {
svelte_element = create_dynamic_element(ctx);
previous_tag = a;
svelte_element.c();
svelte_element.m(svelte_element_anchor.parentNode, svelte_element_anchor);
} else if (safe_not_equal(previous_tag, a)) {
svelte_element.d(1);
svelte_element = create_dynamic_element(ctx);
previous_tag = a;
svelte_element.c();
svelte_element.m(svelte_element_anchor.parentNode, svelte_element_anchor);
} else {
svelte_element.p(ctx, dirty); svelte_element.p(ctx, dirty);
} }
} else if (previous_tag) {
svelte_element.d(1);
svelte_element = null;
previous_tag = a;
}
}, },
i: noop, i: noop,
o: noop, o: noop,
d(detaching) { d(detaching) {
if (detaching) detach(svelte_element_anchor);
if (svelte_element) svelte_element.d(detaching); if (svelte_element) svelte_element.d(detaching);
} }
}; };

@ -2,10 +2,7 @@
import { import {
SvelteComponent, SvelteComponent,
append, append,
assign,
detach, detach,
empty,
get_spread_update,
init, init,
insert, insert,
noop, noop,
@ -17,37 +14,19 @@ import {
function create_dynamic_element(ctx) { function create_dynamic_element(ctx) {
let svelte_element1; let svelte_element1;
let svelte_element0; let svelte_element0;
let svelte_element0_levels = [{ xmlns: "http://www.w3.org/2000/svg" }];
let svelte_element0_data = {};
for (let i = 0; i < svelte_element0_levels.length; i += 1) {
svelte_element0_data = assign(svelte_element0_data, svelte_element0_levels[i]);
}
let svelte_element1_levels = [{ xmlns: "http://www.w3.org/2000/svg" }];
let svelte_element1_data = {};
for (let i = 0; i < svelte_element1_levels.length; i += 1) {
svelte_element1_data = assign(svelte_element1_data, svelte_element1_levels[i]);
}
return { return {
c() { c() {
svelte_element1 = svg_element(/*tag*/ ctx[0].svg); svelte_element1 = svg_element(/*tag*/ ctx[0].svg);
svelte_element0 = svg_element(/*tag*/ ctx[0].path); svelte_element0 = svg_element(/*tag*/ ctx[0].path);
set_svg_attributes(svelte_element0, svelte_element0_data); set_svg_attributes(svelte_element0, { xmlns: "http://www.w3.org/2000/svg" });
set_svg_attributes(svelte_element1, svelte_element1_data); set_svg_attributes(svelte_element1, { xmlns: "http://www.w3.org/2000/svg" });
}, },
m(target, anchor) { m(target, anchor) {
insert(target, svelte_element1, anchor); insert(target, svelte_element1, anchor);
append(svelte_element1, svelte_element0); append(svelte_element1, svelte_element0);
}, },
p(ctx, dirty) { p: noop,
svelte_element0_data = get_spread_update(svelte_element0_levels, [{ xmlns: "http://www.w3.org/2000/svg" }]);
set_svg_attributes(svelte_element0, svelte_element0_data);
svelte_element1_data = get_spread_update(svelte_element1_levels, [{ xmlns: "http://www.w3.org/2000/svg" }]);
set_svg_attributes(svelte_element1, svelte_element1_data);
},
d(detaching) { d(detaching) {
if (detaching) detach(svelte_element1); if (detaching) detach(svelte_element1);
} }
@ -55,45 +34,23 @@ function create_dynamic_element(ctx) {
} }
function create_fragment(ctx) { function create_fragment(ctx) {
let previous_tag = /*tag*/ ctx[0].svg;
let svelte_element_anchor;
let svelte_element = /*tag*/ ctx[0].svg && create_dynamic_element(ctx); let svelte_element = /*tag*/ ctx[0].svg && create_dynamic_element(ctx);
return { return {
c() { c() {
if (svelte_element) svelte_element.c(); if (svelte_element) svelte_element.c();
svelte_element_anchor = empty();
}, },
m(target, anchor) { m(target, anchor) {
if (svelte_element) svelte_element.m(target, anchor); if (svelte_element) svelte_element.m(target, anchor);
insert(target, svelte_element_anchor, anchor);
}, },
p(ctx, [dirty]) { p(ctx, [dirty]) {
if (/*tag*/ ctx[0].svg) { if (/*tag*/ ctx[0].svg) {
if (!previous_tag) {
svelte_element = create_dynamic_element(ctx);
previous_tag = /*tag*/ ctx[0].svg;
svelte_element.c();
svelte_element.m(svelte_element_anchor.parentNode, svelte_element_anchor);
} else if (safe_not_equal(previous_tag, /*tag*/ ctx[0].svg)) {
svelte_element.d(1);
svelte_element = create_dynamic_element(ctx);
previous_tag = /*tag*/ ctx[0].svg;
svelte_element.c();
svelte_element.m(svelte_element_anchor.parentNode, svelte_element_anchor);
} else {
svelte_element.p(ctx, dirty); svelte_element.p(ctx, dirty);
} }
} else if (previous_tag) {
svelte_element.d(1);
svelte_element = null;
previous_tag = /*tag*/ ctx[0].svg;
}
}, },
i: noop, i: noop,
o: noop, o: noop,
d(detaching) { d(detaching) {
if (detaching) detach(svelte_element_anchor);
if (svelte_element) svelte_element.d(detaching); if (svelte_element) svelte_element.d(detaching);
} }
}; };

@ -0,0 +1,244 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
assign,
detach,
element,
empty,
get_spread_update,
init,
insert,
noop,
safe_not_equal,
set_dynamic_element_data,
space,
toggle_class
} from "svelte/internal";
function create_dynamic_element_3(ctx) {
let svelte_element;
return {
c() {
svelte_element = element(static_value);
set_dynamic_element_data(static_value)(svelte_element, { static_value, ...static_obj });
toggle_class(svelte_element, "foo", static_value);
},
m(target, anchor) {
insert(target, svelte_element, anchor);
},
p: noop,
d(detaching) {
if (detaching) detach(svelte_element);
}
};
}
// (10:0) <svelte:element this={dynamic_value} {static_value} {...static_obj} class:foo={static_value} />
function create_dynamic_element_2(ctx) {
let svelte_element;
return {
c() {
svelte_element = element(/*dynamic_value*/ ctx[0]);
set_dynamic_element_data(/*dynamic_value*/ ctx[0])(svelte_element, { static_value, ...static_obj });
toggle_class(svelte_element, "foo", static_value);
},
m(target, anchor) {
insert(target, svelte_element, anchor);
},
p: noop,
d(detaching) {
if (detaching) detach(svelte_element);
}
};
}
// (12:0) <svelte:element this={static_value} {dynamic_value} {...dynamic_obj} class:foo={dynamic_value} />
function create_dynamic_element_1(ctx) {
let svelte_element;
let svelte_element_levels = [{ dynamic_value: /*dynamic_value*/ ctx[0] }, /*dynamic_obj*/ ctx[1]];
let svelte_element_data = {};
for (let i = 0; i < svelte_element_levels.length; i += 1) {
svelte_element_data = assign(svelte_element_data, svelte_element_levels[i]);
}
return {
c() {
svelte_element = element(static_value);
set_dynamic_element_data(static_value)(svelte_element, svelte_element_data);
toggle_class(svelte_element, "foo", /*dynamic_value*/ ctx[0]);
},
m(target, anchor) {
insert(target, svelte_element, anchor);
},
p(ctx, dirty) {
set_dynamic_element_data(static_value)(svelte_element, svelte_element_data = get_spread_update(svelte_element_levels, [
dirty & /*dynamic_value*/ 1 && { dynamic_value: /*dynamic_value*/ ctx[0] },
dirty & /*dynamic_obj*/ 2 && /*dynamic_obj*/ ctx[1]
]));
toggle_class(svelte_element, "foo", /*dynamic_value*/ ctx[0]);
},
d(detaching) {
if (detaching) detach(svelte_element);
}
};
}
// (14:0) <svelte:element this={dynamic_value} {dynamic_value} {...dynamic_obj} class:foo={dynamic_value} />
function create_dynamic_element(ctx) {
let svelte_element;
let svelte_element_levels = [{ dynamic_value: /*dynamic_value*/ ctx[0] }, /*dynamic_obj*/ ctx[1]];
let svelte_element_data = {};
for (let i = 0; i < svelte_element_levels.length; i += 1) {
svelte_element_data = assign(svelte_element_data, svelte_element_levels[i]);
}
return {
c() {
svelte_element = element(/*dynamic_value*/ ctx[0]);
set_dynamic_element_data(/*dynamic_value*/ ctx[0])(svelte_element, svelte_element_data);
toggle_class(svelte_element, "foo", /*dynamic_value*/ ctx[0]);
},
m(target, anchor) {
insert(target, svelte_element, anchor);
},
p(ctx, dirty) {
set_dynamic_element_data(/*dynamic_value*/ ctx[0])(svelte_element, svelte_element_data = get_spread_update(svelte_element_levels, [
dirty & /*dynamic_value*/ 1 && { dynamic_value: /*dynamic_value*/ ctx[0] },
dirty & /*dynamic_obj*/ 2 && /*dynamic_obj*/ ctx[1]
]));
toggle_class(svelte_element, "foo", /*dynamic_value*/ ctx[0]);
},
d(detaching) {
if (detaching) detach(svelte_element);
}
};
}
function create_fragment(ctx) {
let t0;
let previous_tag = /*dynamic_value*/ ctx[0];
let t1;
let t2;
let previous_tag_1 = /*dynamic_value*/ ctx[0];
let svelte_element3_anchor;
let svelte_element0 = static_value && create_dynamic_element_3(ctx);
let svelte_element1 = /*dynamic_value*/ ctx[0] && create_dynamic_element_2(ctx);
let svelte_element2 = static_value && create_dynamic_element_1(ctx);
let svelte_element3 = /*dynamic_value*/ ctx[0] && create_dynamic_element(ctx);
return {
c() {
if (svelte_element0) svelte_element0.c();
t0 = space();
if (svelte_element1) svelte_element1.c();
t1 = space();
if (svelte_element2) svelte_element2.c();
t2 = space();
if (svelte_element3) svelte_element3.c();
svelte_element3_anchor = empty();
},
m(target, anchor) {
if (svelte_element0) svelte_element0.m(target, anchor);
insert(target, t0, anchor);
if (svelte_element1) svelte_element1.m(target, anchor);
insert(target, t1, anchor);
if (svelte_element2) svelte_element2.m(target, anchor);
insert(target, t2, anchor);
if (svelte_element3) svelte_element3.m(target, anchor);
insert(target, svelte_element3_anchor, anchor);
},
p(ctx, [dirty]) {
if (static_value) {
svelte_element0.p(ctx, dirty);
}
if (/*dynamic_value*/ ctx[0]) {
if (!previous_tag) {
svelte_element1 = create_dynamic_element_2(ctx);
previous_tag = /*dynamic_value*/ ctx[0];
svelte_element1.c();
svelte_element1.m(t1.parentNode, t1);
} else if (safe_not_equal(previous_tag, /*dynamic_value*/ ctx[0])) {
svelte_element1.d(1);
svelte_element1 = create_dynamic_element_2(ctx);
previous_tag = /*dynamic_value*/ ctx[0];
svelte_element1.c();
svelte_element1.m(t1.parentNode, t1);
} else {
svelte_element1.p(ctx, dirty);
}
} else if (previous_tag) {
svelte_element1.d(1);
svelte_element1 = null;
previous_tag = /*dynamic_value*/ ctx[0];
}
if (static_value) {
svelte_element2.p(ctx, dirty);
}
if (/*dynamic_value*/ ctx[0]) {
if (!previous_tag_1) {
svelte_element3 = create_dynamic_element(ctx);
previous_tag_1 = /*dynamic_value*/ ctx[0];
svelte_element3.c();
svelte_element3.m(svelte_element3_anchor.parentNode, svelte_element3_anchor);
} else if (safe_not_equal(previous_tag_1, /*dynamic_value*/ ctx[0])) {
svelte_element3.d(1);
svelte_element3 = create_dynamic_element(ctx);
previous_tag_1 = /*dynamic_value*/ ctx[0];
svelte_element3.c();
svelte_element3.m(svelte_element3_anchor.parentNode, svelte_element3_anchor);
} else {
svelte_element3.p(ctx, dirty);
}
} else if (previous_tag_1) {
svelte_element3.d(1);
svelte_element3 = null;
previous_tag_1 = /*dynamic_value*/ ctx[0];
}
},
i: noop,
o: noop,
d(detaching) {
if (svelte_element0) svelte_element0.d(detaching);
if (detaching) detach(t0);
if (svelte_element1) svelte_element1.d(detaching);
if (detaching) detach(t1);
if (svelte_element2) svelte_element2.d(detaching);
if (detaching) detach(t2);
if (detaching) detach(svelte_element3_anchor);
if (svelte_element3) svelte_element3.d(detaching);
}
};
}
let static_value = 'a';
function instance($$self, $$props, $$invalidate) {
let { dynamic_value } = $$props;
let { dynamic_obj } = $$props;
let static_obj = {};
$$self.$$set = $$props => {
if ('dynamic_value' in $$props) $$invalidate(0, dynamic_value = $$props.dynamic_value);
if ('dynamic_obj' in $$props) $$invalidate(1, dynamic_obj = $$props.dynamic_obj);
};
return [dynamic_value, dynamic_obj, static_obj];
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, { dynamic_value: 0, dynamic_obj: 1 });
}
}
export default Component;

@ -0,0 +1,14 @@
<script>
export let dynamic_value;
export let dynamic_obj;
let static_value = 'a';
let static_obj = {};
</script>
<svelte:element this={static_value} {static_value} {...static_obj} class:foo={static_value} />
<svelte:element this={dynamic_value} {static_value} {...static_obj} class:foo={static_value} />
<svelte:element this={static_value} {dynamic_value} {...dynamic_obj} class:foo={dynamic_value} />
<svelte:element this={dynamic_value} {dynamic_value} {...dynamic_obj} class:foo={dynamic_value} />

@ -30,23 +30,31 @@ function create_fragment(ctx) {
video_updating = true; video_updating = true;
} }
/*video_timeupdate_handler*/ ctx[4].call(video); /*video_timeupdate_handler*/ ctx[5].call(video);
} }
return { return {
c() { c() {
video = element("video"); video = element("video");
if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[5].call(video)); if (/*videoHeight*/ ctx[1] === void 0 || /*videoWidth*/ ctx[2] === void 0) add_render_callback(() => /*video_resize_handler*/ ctx[6].call(video));
add_render_callback(() => /*video_elementresize_handler*/ ctx[6].call(video)); add_render_callback(() => /*video_elementresize_handler*/ ctx[7].call(video));
if (/*readyState*/ ctx[4] === void 0) add_render_callback(() => /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8].call(video));
}, },
m(target, anchor) { m(target, anchor) {
insert(target, video, anchor); insert(target, video, anchor);
video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[6].bind(video)); video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[7].bind(video));
if (!mounted) { if (!mounted) {
dispose = [ dispose = [
listen(video, "timeupdate", video_timeupdate_handler), listen(video, "timeupdate", video_timeupdate_handler),
listen(video, "resize", /*video_resize_handler*/ ctx[5]) listen(video, "resize", /*video_resize_handler*/ ctx[6]),
listen(video, "loadedmetadata", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "loadeddata", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "canplay", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "canplaythrough", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "playing", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "waiting", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8]),
listen(video, "emptied", /*video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler*/ ctx[8])
]; ];
mounted = true; mounted = true;
@ -75,6 +83,7 @@ function instance($$self, $$props, $$invalidate) {
let { videoHeight } = $$props; let { videoHeight } = $$props;
let { videoWidth } = $$props; let { videoWidth } = $$props;
let { offsetWidth } = $$props; let { offsetWidth } = $$props;
let { readyState } = $$props;
function video_timeupdate_handler() { function video_timeupdate_handler() {
currentTime = this.currentTime; currentTime = this.currentTime;
@ -93,11 +102,17 @@ function instance($$self, $$props, $$invalidate) {
$$invalidate(3, offsetWidth); $$invalidate(3, offsetWidth);
} }
function video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler() {
readyState = this.readyState;
$$invalidate(4, readyState);
}
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ('currentTime' in $$props) $$invalidate(0, currentTime = $$props.currentTime); if ('currentTime' in $$props) $$invalidate(0, currentTime = $$props.currentTime);
if ('videoHeight' in $$props) $$invalidate(1, videoHeight = $$props.videoHeight); if ('videoHeight' in $$props) $$invalidate(1, videoHeight = $$props.videoHeight);
if ('videoWidth' in $$props) $$invalidate(2, videoWidth = $$props.videoWidth); if ('videoWidth' in $$props) $$invalidate(2, videoWidth = $$props.videoWidth);
if ('offsetWidth' in $$props) $$invalidate(3, offsetWidth = $$props.offsetWidth); if ('offsetWidth' in $$props) $$invalidate(3, offsetWidth = $$props.offsetWidth);
if ('readyState' in $$props) $$invalidate(4, readyState = $$props.readyState);
}; };
return [ return [
@ -105,9 +120,11 @@ function instance($$self, $$props, $$invalidate) {
videoHeight, videoHeight,
videoWidth, videoWidth,
offsetWidth, offsetWidth,
readyState,
video_timeupdate_handler, video_timeupdate_handler,
video_resize_handler, video_resize_handler,
video_elementresize_handler video_elementresize_handler,
video_loadedmetadata_loadeddata_canplay_canplaythrough_playing_waiting_emptied_handler
]; ];
} }
@ -119,7 +136,8 @@ class Component extends SvelteComponent {
currentTime: 0, currentTime: 0,
videoHeight: 1, videoHeight: 1,
videoWidth: 2, videoWidth: 2,
offsetWidth: 3 offsetWidth: 3,
readyState: 4
}); });
} }
} }

@ -3,6 +3,7 @@
export let videoHeight; export let videoHeight;
export let videoWidth; export let videoWidth;
export let offsetWidth; export let offsetWidth;
export let readyState;
</script> </script>
<video bind:currentTime bind:videoHeight bind:videoWidth bind:offsetWidth/> <video bind:currentTime bind:videoHeight bind:videoWidth bind:offsetWidth bind:readyState/>

@ -0,0 +1,25 @@
export default {
async test({ assert, target, component, window }) {
const [input1, input2, input3] = target.querySelectorAll('input');
const event = new window.Event('change');
function validate_inputs(v1, v2, v3) {
assert.equal(input1.checked, v1);
assert.equal(input2.checked, v2);
assert.equal(input3.checked, v3);
}
assert.deepEqual(component.values.inner, []);
validate_inputs(false, false, false);
component.values = { inner: undefined };
assert.deepEqual(component.values.inner, undefined);
validate_inputs(false, false, false);
input1.checked = true;
await input1.dispatchEvent(event);
assert.deepEqual(component.values.inner, ['first']);
validate_inputs(true, false, false);
}
};

@ -0,0 +1,15 @@
<script>
export let values = {
inner: []
};
</script>
<input type='checkbox' value='first' bind:group={values.inner} />
<input type='checkbox' value='second' bind:group={values.inner} />
<input type='checkbox' value='third' bind:group={values.inner} />
<div>
{#each ['first', 'second', 'third'] as k}
<span>{k}</span>
{/each}
</div>

@ -1,5 +1,5 @@
<script> <script>
let primary = true; export let primary = true;
let elem; let elem;
</script> </script>

@ -0,0 +1,17 @@
export default {
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.deepEqual(component.logs, ['click_1', 'click_2']);
component.click_2 = () => component.logs.push('22');
await button.dispatchEvent(event);
assert.deepEqual(component.logs, ['click_1', 'click_2', 'click_1', '22']);
component.click_1 = () => component.logs.push('11');
await button.dispatchEvent(event);
assert.deepEqual(component.logs, ['click_1', 'click_2', 'click_1', '22', '11', '22']);
}
};

@ -0,0 +1,22 @@
<script>
export let logs = [];
export let click_1 = () => {
logs.push('click_1');
}
export let click_2 = () => {
logs.push('click_2');
}
export let click_3 = () => {
logs.push('click_3');
}
</script>
<button
on:click={click_1}
on:click|stopImmediatePropagation={click_2}
on:click={click_3}>
click me
</button>

@ -0,0 +1,19 @@
export default {
html: `
<span data-xxx="&amp;copy=value" style="&amp;copy=value"></span>
<span data-xxx="&amp;copy=value" style="&amp;copy=value"></span>
<span data-xxx="©" style="©"></span>
<span data-xxx="©=value" style="©=value"></span>
<span data-xxx="&amp;copyotherstring=value" style="&amp;copyotherstring=value"></span>
<span data-xxx="&amp;copy123=value" style="&amp;copy123=value"></span>
<span data-xxx="&amp;rect=value" style="&amp;rect=value"></span>
<span data-xxx="▭=value" style="▭=value"></span>
`
};

@ -0,0 +1,15 @@
<span data-xxx="&copy=value" style="&copy=value"></span>
<span data-xxx="&copy=value" style="&copy=value"></span>
<span data-xxx="&copy" style="&copy"></span>
<span data-xxx="&copy;=value" style="&copy;=value"></span>
<span data-xxx="&copyotherstring=value" style="&copyotherstring=value"></span>
<span data-xxx="&copy123=value" style="&copy123=value"></span>
<span data-xxx="&rect=value" style="&rect=value"></span>
<span data-xxx="&rect;=value" style="&rect;=value"></span>

@ -4,11 +4,25 @@ export default {
<span>*</span> <span>*</span>
<span>*</span> <span>*</span>
<span>*</span> <span>*</span>
<span>*</span>
<span></span> <span></span>
<span>A</span> <span>A</span>
<span></span> <span></span>
<span></span>
<span>&amp;stringnotanentity;</span>
<span>different &amp;rect and </span>
<span>©otherstring</span>
<span>©=otherstring</span>
<span>©=otherstring</span>
<span>©123</span>
<span>&amp;notanentity;</span> <span>Ÿotherstring</span>
` `
}; };

@ -1,10 +1,24 @@
<span>&ast;</span> <span>&ast;</span>
<span>&midast;</span> <span>&midast;</span>
<span>&#x0002A;</span> <span>&#x0002A;</span>
<span>&#x0002A</span>
<span>&#42;</span> <span>&#42;</span>
<span>&#10;</span> <span>&#10;</span>
<span>&#65;</span> <span>&#65;</span>
<span>&#128;</span> <span>&#128;</span>
<span>&#128</span>
<span>&notanentity;</span> <span>&stringnotanentity;</span>
<span>different &rect and &rect;</span>
<span>&copyotherstring</span>
<span>&copy=otherstring</span>
<span>&copy;=otherstring</span>
<span>&copy123</span>
<span>&#x9fotherstring</span>

@ -6,6 +6,7 @@ export default {
<div>foo</div> <div>foo</div>
</template> </template>
<template id="t2">123</template> <template id="t2">123</template>
<template id="t3">1<b>B</b>1</template>
`, `,
test({ assert, target }) { test({ assert, target }) {
@ -27,5 +28,16 @@ export default {
assert.equal(template2.content.firstChild.textContent, '123'); assert.equal(template2.content.firstChild.textContent, '123');
assert.htmlEqual(template2.innerHTML, '123'); assert.htmlEqual(template2.innerHTML, '123');
const template3 = target.querySelector('#t3');
assert.equal(template3.childNodes.length, 0);
assert.equal(template3.content.childNodes.length, 3);
// test: (with hydration from ssr rendered html)
// out of order render.
// <template>1{@html '2'}3</template> may render as <template>321</template> for ssr+hydration case.
// we bypass it by using symmetric siblings. hence <template> is not fully stable for this edge case.
assert.equal(template3.content.childNodes[0].textContent, '1');
assert.equal(template3.content.childNodes[1].outerHTML, '<b>B</b>');
assert.equal(template3.content.childNodes[2].textContent, '1');
} }
}; };

@ -2,3 +2,4 @@
<div>foo</div> <div>foo</div>
</template> </template>
<template id="t2">123</template> <template id="t2">123</template>
<template id="t3">1{@html '<b>B</b>'}1</template>

@ -7,11 +7,10 @@
<input aria-activedescendant="some-id" tabindex="0" /> <input aria-activedescendant="some-id" tabindex="0" />
<input aria-activedescendant="some-id" tabindex={-1} /> <input aria-activedescendant="some-id" tabindex={-1} />
<input aria-activedescendant="some-id" tabindex="-1" /> <input aria-activedescendant="some-id" tabindex="-1" />
<svelte:element this={Math.random() ? 'input' : 'button'} aria-activedescendant="some-id" />
<div /> <div />
<div aria-activedescendant="some-id" role="tablist" tabindex={-1} /> <div aria-activedescendant="some-id" role="tablist" tabindex={-1} />
<div aria-activedescendant="some-id" role="tablist" tabindex="-1" /> <div aria-activedescendant="some-id" role="tablist" tabindex="-1" />
<!-- INVALID --> <!-- INVALID -->
<div aria-activedescendant="some-id" /> <div aria-activedescendant="some-id" />

@ -47,3 +47,5 @@
<div on:click={noop} role="presentation" /> <div on:click={noop} role="presentation" />
<div on:click={noop} role="none" /> <div on:click={noop} role="none" />
<div on:click={noop} role={dynamicRole} /> <div on:click={noop} role={dynamicRole} />
<svelte:element this={Math.random() ? 'button' : 'div'} on:click={noop} />

@ -8,6 +8,7 @@
<div role='article' tabindex='-1' /> <div role='article' tabindex='-1' />
<article tabindex='-1' /> <article tabindex='-1' />
<div role="tabpanel" tabindex='0' /> <div role="tabpanel" tabindex='0' />
<svelte:element this={Math.random() ? 'button' : 'div'} tabindex="0" />
<!-- invalid --> <!-- invalid -->
<div tabindex='0' /> <div tabindex='0' />
<div role='article' tabindex='0' /> <div role='article' tabindex='0' />

@ -3,48 +3,48 @@
"code": "a11y-no-noninteractive-tabindex", "code": "a11y-no-noninteractive-tabindex",
"end": { "end": {
"column": 20, "column": 20,
"line": 12 "line": 13
}, },
"message": "A11y: noninteractive element cannot have nonnegative tabIndex value", "message": "A11y: noninteractive element cannot have nonnegative tabIndex value",
"start": { "start": {
"column": 0, "column": 0,
"line": 12 "line": 13
} }
}, },
{ {
"code": "a11y-no-noninteractive-tabindex", "code": "a11y-no-noninteractive-tabindex",
"end": { "end": {
"column": 35, "column": 35,
"line": 13 "line": 14
}, },
"message": "A11y: noninteractive element cannot have nonnegative tabIndex value", "message": "A11y: noninteractive element cannot have nonnegative tabIndex value",
"start": { "start": {
"column": 0, "column": 0,
"line": 13 "line": 14
} }
}, },
{ {
"code": "a11y-no-noninteractive-tabindex", "code": "a11y-no-noninteractive-tabindex",
"end": { "end": {
"column": 24, "column": 24,
"line": 14 "line": 15
}, },
"message": "A11y: noninteractive element cannot have nonnegative tabIndex value", "message": "A11y: noninteractive element cannot have nonnegative tabIndex value",
"start": { "start": {
"column": 0, "column": 0,
"line": 14 "line": 15
} }
}, },
{ {
"code": "a11y-no-noninteractive-tabindex", "code": "a11y-no-noninteractive-tabindex",
"end": { "end": {
"column": 26, "column": 26,
"line": 15 "line": 16
}, },
"message": "A11y: noninteractive element cannot have nonnegative tabIndex value", "message": "A11y: noninteractive element cannot have nonnegative tabIndex value",
"start": { "start": {
"column": 0, "column": 0,
"line": 15 "line": 16
} }
} }
] ]

@ -8,3 +8,4 @@
<div role="meter" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div> <div role="meter" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
<div role="scrollbar" aria-controls="panel" aria-valuenow="50"></div> <div role="scrollbar" aria-controls="panel" aria-valuenow="50"></div>
<input role="switch" type="checkbox" /> <input role="switch" type="checkbox" />
<svelte:element this={Math.random() ? 'input' : 'div'} role="checkbox" />

@ -1 +1,6 @@
<!-- valid -->
<th scope />
<svelte:element this={Math.random() ? 'th' : 'td'} scope />
<!-- invalid -->
<div scope/> <div scope/>

@ -3,11 +3,11 @@
"code": "a11y-misplaced-scope", "code": "a11y-misplaced-scope",
"message": "A11y: The scope attribute should only be used with <th> elements", "message": "A11y: The scope attribute should only be used with <th> elements",
"start": { "start": {
"line": 1, "line": 6,
"column": 5 "column": 5
}, },
"end": { "end": {
"line": 1, "line": 6,
"column": 10 "column": 10
} }
} }

@ -4,14 +4,11 @@
"message": "You are assigning to a const", "message": "You are assigning to a const",
"start": { "start": {
"line": 3, "line": 3,
"column": 1, "column": 1
"character": 31
}, },
"end": { "end": {
"line": 3, "line": 3,
"column": 33, "column": 33
"character": 63 }
},
"pos": 31
} }
] ]

@ -4,14 +4,11 @@
"message": "You are assigning to a const", "message": "You are assigning to a const",
"start": { "start": {
"line": 3, "line": 3,
"column": 1, "column": 1
"character": 43
}, },
"end": { "end": {
"line": 3, "line": 3,
"column": 42, "column": 42
"character": 84 }
},
"pos": 43
} }
] ]

@ -16,3 +16,15 @@
<ExportLet /> <ExportLet />
<Reactive /> <Reactive />
<svelte:component this={Let} /> <svelte:component this={Let} />
<!-- Here, we test to see if svelte-ignore works with reactive-component -->
<!-- svelte-ignore reactive-component -->
<Let />
<div>
<!-- svelte-ignore reactive-component -->
<ExportLet />
<div>
<!-- svelte-ignore reactive-component -->
<Reactive />
</div>
</div>

@ -0,0 +1,12 @@
[{
"code": "css-invalid-global-selector-position",
"message": ":global(...) not at the start of a selector sequence should not contain type or universal selectors",
"start": {
"line": 2,
"column": 5
},
"end": {
"line": 2,
"column": 17
}
}]

@ -0,0 +1,5 @@
<style>
.foo:global(div) {
color: red;
}
</style>

@ -1,5 +1,5 @@
[{ [{
"message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive, nonpassive, self or trusted", "message": "Valid event modifiers are preventDefault, stopPropagation, stopImmediatePropagation, capture, once, passive, nonpassive, self or trusted",
"code": "invalid-event-modifier", "code": "invalid-event-modifier",
"start": { "start": {
"line": 1, "line": 1,

Loading…
Cancel
Save