Skip to content

Commit 418f4c2

Browse files
committed
Merge branch 'master' into version-4
2 parents 37c8bd7 + 4537eb7 commit 418f4c2

File tree

52 files changed

+878
-69
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+878
-69
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# HEADS UP: BIG RESTRUCTURING UNDERWAY
2+
3+
The Svelte repo is currently in the process of heavy restructuring for Svelte 4. After that, work on Svelte 5 will likely change a lot on the compiler aswell. For that reason, please don't open PRs that are large in scope, touch more than a couple of files etc. In other words, bug fixes are fine, but feature PRs will likely not be merged.
4+
15
### Before submitting the PR, please make sure you do the following
26
- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
37
- [ ] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.

CHANGELOG.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,18 @@
2323
* Fix transitions so that they don't require a `style-src 'unsafe-inline'` Content Security Policy (CSP) ([#6662](https://github.com/sveltejs/svelte/issues/6662)).
2424
* Explicitly disallow `var` declarations extending the reactive statement scope ([#6800](https://github.com/sveltejs/svelte/pull/6800))
2525

26-
## Unreleased (3.0)
27-
28-
* Handle `width`/`height` attributes when spreading ([#6752](https://github.com/sveltejs/svelte/issues/6752))
29-
* Add support for resize observer bindings (`<div bind:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize>`) ([#8022](https://github.com/sveltejs/svelte/pull/8022))
30-
26+
## 3.59.0
27+
28+
* Add `ResizeObserver` bindings `contentRect`/`contentBoxSize`/`borderBoxSize`/`devicePixelContentBoxSize` ([#8022](https://github.com/sveltejs/svelte/pull/8022))
29+
* Add `devicePixelRatio` binding for `<svelte:window>` ([#8285](https://github.com/sveltejs/svelte/issues/8285))
30+
* Add `fullscreenElement` and `visibilityState` bindings for `<svelte:document>` ([#8507](https://github.com/sveltejs/svelte/pull/8507))
31+
* Add `a11y-autocomplete-valid` warning ([#8520](https://github.com/sveltejs/svelte/pull/8520))
32+
* Fix handling of `width`/`height` attributes when spreading ([#6752](https://github.com/sveltejs/svelte/issues/6752))
33+
* Fix updating of interpolated `style:` directive when using spread ([#8438](https://github.com/sveltejs/svelte/issues/8438))
34+
* Remove `style:` directive property when value is `undefined` ([#8462](https://github.com/sveltejs/svelte/issues/8462))
35+
* Fix type of `VERSION` compiler export ([#8498](https://github.com/sveltejs/svelte/issues/8498))
36+
* Relax `a11y-no-redundant-roles` warning ([#8536](https://github.com/sveltejs/svelte/pull/8536))
37+
* Handle nested array rest destructuring ([#8552](https://github.com/sveltejs/svelte/issues/8552), [#8554](https://github.com/sveltejs/svelte/issues/8554))
3138
## 3.58.0
3239

3340
* Add `bind:innerText` for `contenteditable` elements ([#3311](https://github.com/sveltejs/svelte/issues/3311))

CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ When [opening a new issue](https://github.com/sveltejs/svelte/issues/new/choose)
6262

6363
## Pull requests
6464

65+
> HEADS UP: The Svelte repo is currently in the process of heavy restructuring for Svelte 4. After that, work on Svelte 5 will likely change a lot on the compiler aswell. For that reason, please don't open PRs that are large in scope, touch more than a couple of files etc. In other words, bug fixes are fine, but feature PRs will likely not be merged.
66+
6567
### Proposing a change
6668

6769
If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, you can also file an issue with [feature template](https://github.com/sveltejs/svelte/issues/new?template=feature_request.yml).

elements/index.d.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1081,11 +1081,17 @@ export interface SvelteMediaTimeRange {
10811081
end: number;
10821082
}
10831083

1084+
export interface SvelteDocumentAttributes extends HTMLAttributes<Document> {
1085+
readonly 'bind:fullscreenElement'?: Document['fullscreenElement'] | undefined | null;
1086+
readonly 'bind:visibilityState'?: Document['visibilityState'] | undefined | null;
1087+
}
1088+
10841089
export interface SvelteWindowAttributes extends HTMLAttributes<Window> {
10851090
readonly 'bind:innerWidth'?: Window['innerWidth'] | undefined | null;
10861091
readonly 'bind:innerHeight'?: Window['innerHeight'] | undefined | null;
10871092
readonly 'bind:outerWidth'?: Window['outerWidth'] | undefined | null;
10881093
readonly 'bind:outerHeight'?: Window['outerHeight'] | undefined | null;
1094+
readonly 'bind:devicePixelRatio'?: Window['devicePixelRatio'] | undefined | null;
10891095
'bind:scrollX'?: Window['scrollX'] | undefined | null;
10901096
'bind:scrollY'?: Window['scrollY'] | undefined | null;
10911097
readonly 'bind:online'?: Window['navigator']['onLine'] | undefined | null;
@@ -1594,7 +1600,7 @@ export interface SvelteHTMLElements {
15941600

15951601
// Svelte specific
15961602
'svelte:window': SvelteWindowAttributes;
1597-
'svelte:document': HTMLAttributes<Document>;
1603+
'svelte:document': SvelteDocumentAttributes;
15981604
'svelte:body': HTMLAttributes<HTMLElement>;
15991605
'svelte:fragment': { slot?: string };
16001606
'svelte:options': {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "svelte",
3-
"version": "3.58.0",
3+
"version": "3.59.0",
44
"description": "Cybernetically enhanced web apps",
55
"module": "index.mjs",
66
"main": "index",

site/content/docs/02-component-format.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Svelte uses the `export` keyword to mark a variable declaration as a *property*
4242

4343
---
4444

45-
You can specify a default initial value for a prop. It will be used if the component's consumer doesn't specify the prop on the component (or if its initial value is `undefined`) when instantiating the component. Note that whenever a prop is removed by the consumer, its value is set to `undefined` rather than the initial value.
45+
You can specify a default initial value for a prop. It will be used if the component's consumer doesn't specify the prop on the component (or if its initial value is `undefined`) when instantiating the component. Note that if the values of props are subsequently updated, then any prop whose value is not specified will be set to `undefined` (rather than its initial value).
4646

4747
In development mode (see the [compiler options](/docs#compile-time-svelte-compile)), a warning will be printed if no default initial value is provided and the consumer does not specify a value. To squelch this warning, ensure that a default initial value is specified, even if it is `undefined`.
4848

site/content/docs/03-template-syntax.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,8 @@ Inputs that work together can use `bind:group`.
823823
<input type="checkbox" bind:group={fillings} value="Guac (extra)">
824824
```
825825

826+
> `bind:group` only works if the inputs are in the same Svelte component.
827+
826828
#### bind:this
827829

828830
```sv
@@ -1742,6 +1744,7 @@ You can also bind to the following properties:
17421744
* `scrollX`
17431745
* `scrollY`
17441746
* `online` — an alias for `window.navigator.onLine`
1747+
* `devicePixelRatio`
17451748

17461749
All except `scrollX` and `scrollY` are readonly.
17471750

@@ -1756,6 +1759,9 @@ All except `scrollX` and `scrollY` are readonly.
17561759
```sv
17571760
<svelte:document on:event={handler}/>
17581761
```
1762+
```sv
1763+
<svelte:document bind:prop={value}/>
1764+
```
17591765

17601766
---
17611767

@@ -1770,6 +1776,15 @@ As with `<svelte:window>`, this element may only appear the top level of your co
17701776
/>
17711777
```
17721778

1779+
---
1780+
1781+
You can also bind to the following properties:
1782+
1783+
* `fullscreenElement`
1784+
* `visibilityState`
1785+
1786+
All are readonly.
1787+
17731788
### `<svelte:body>`
17741789

17751790
```sv

src/compiler/compile/Component.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import TemplateScope from './nodes/shared/TemplateScope';
2626
import fuzzymatch from '../utils/fuzzymatch';
2727
import get_object from './utils/get_object';
2828
import Slot from './nodes/Slot';
29-
import { Node, ImportDeclaration, ExportNamedDeclaration, Identifier, ExpressionStatement, AssignmentExpression, Literal, Property, RestElement, ExportDefaultDeclaration, ExportAllDeclaration, FunctionDeclaration, FunctionExpression, VariableDeclarator, ObjectExpression } from 'estree';
29+
import { Node, ImportDeclaration, ExportNamedDeclaration, Identifier, ExpressionStatement, AssignmentExpression, Literal, Property, RestElement, ExportDefaultDeclaration, ExportAllDeclaration, FunctionDeclaration, FunctionExpression, VariableDeclarator, ObjectExpression, Pattern, Expression } from 'estree';
3030
import add_to_set from './utils/add_to_set';
3131
import check_graph_for_cycles from './utils/check_graph_for_cycles';
3232
import { print, b } from 'code-red';
@@ -1036,7 +1036,7 @@ export default class Component {
10361036
const inserts = [];
10371037
const props = [];
10381038

1039-
function add_new_props(exported, local, default_value) {
1039+
function add_new_props(exported: Identifier, local: Pattern, default_value: Expression) {
10401040
props.push({
10411041
type: 'Property',
10421042
method: false,
@@ -1066,7 +1066,7 @@ export default class Component {
10661066
for (let index = 0; index < node.declarations.length; index++) {
10671067
const declarator = node.declarations[index];
10681068
if (declarator.id.type !== 'Identifier') {
1069-
function get_new_name(local) {
1069+
function get_new_name(local: Identifier): Identifier {
10701070
const variable = component.var_lookup.get(local.name);
10711071
if (variable.subscribable) {
10721072
inserts.push(get_insert(variable));
@@ -1080,7 +1080,7 @@ export default class Component {
10801080
return local;
10811081
}
10821082

1083-
function rename_identifiers(param: Node) {
1083+
function rename_identifiers(param: Pattern) {
10841084
switch (param.type) {
10851085
case 'ObjectPattern': {
10861086
const handle_prop = (prop: Property | RestElement) => {
@@ -1089,15 +1089,15 @@ export default class Component {
10891089
} else if (prop.value.type === 'Identifier') {
10901090
prop.value = get_new_name(prop.value);
10911091
} else {
1092-
rename_identifiers(prop.value);
1092+
rename_identifiers(prop.value as Pattern);
10931093
}
10941094
};
10951095

10961096
param.properties.forEach(handle_prop);
10971097
break;
10981098
}
10991099
case 'ArrayPattern': {
1100-
const handle_element = (element: Node, index: number, array: Node[]) => {
1100+
const handle_element = (element: Pattern | null, index: number, array: Array<Pattern | null>) => {
11011101
if (element) {
11021102
if (element.type === 'Identifier') {
11031103
array[index] = get_new_name(element);
@@ -1112,7 +1112,11 @@ export default class Component {
11121112
}
11131113

11141114
case 'RestElement':
1115-
param.argument = get_new_name(param.argument);
1115+
if (param.argument.type === 'Identifier') {
1116+
param.argument = get_new_name(param.argument);
1117+
} else {
1118+
rename_identifiers(param.argument);
1119+
}
11161120
break;
11171121

11181122
case 'AssignmentPattern':

src/compiler/compile/compiler_warnings.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ export default {
170170
code: 'a11y-missing-attribute',
171171
message: `A11y: <${name}> element should have ${article} ${sequence} attribute`
172172
}),
173+
a11y_autocomplete_valid: (type: null | true | string, value: null | true | string) => ({
174+
code: 'a11y-autocomplete-valid',
175+
message: `A11y: The value '${value}' is not supported by the attribute 'autocomplete' on element <input type="${type}">`
176+
}),
173177
a11y_img_redundant_alt: {
174178
code: 'a11y-img-redundant-alt',
175179
message: 'A11y: Screenreaders already announce <img> elements as an image.'
@@ -228,7 +232,7 @@ export default {
228232
},
229233
invalid_rest_eachblock_binding: (rest_element_name: string) => ({
230234
code: 'invalid-rest-eachblock-binding',
231-
message: `...${rest_element_name} operator will create a new object and binding propagation with original object will not work`
235+
message: `The rest operator (...) will create a new object and binding '${rest_element_name}' with the original object will not work`
232236
}),
233237
avoid_mouse_events_on_document: {
234238
code: 'avoid-mouse-events-on-document',

src/compiler/compile/nodes/Binding.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { TemplateNode } from '../../interfaces';
99
import Element from './Element';
1010
import InlineComponent from './InlineComponent';
1111
import Window from './Window';
12+
import Document from './Document';
1213
import { clone } from '../../utils/clone';
1314
import compiler_errors from '../compiler_errors';
1415
import compiler_warnings from '../compiler_warnings';
@@ -36,7 +37,7 @@ export default class Binding extends Node {
3637
is_contextual: boolean;
3738
is_readonly: boolean;
3839

39-
constructor(component: Component, parent: Element | InlineComponent | Window, scope: TemplateScope, info: TemplateNode) {
40+
constructor(component: Component, parent: Element | InlineComponent | Window | Document, scope: TemplateScope, info: TemplateNode) {
4041
super(component, parent, scope, info);
4142

4243
if (info.expression.type !== 'Identifier' && info.expression.type !== 'MemberExpression') {

src/compiler/compile/nodes/Document.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import Node from './shared/Node';
2+
import Binding from './Binding';
23
import EventHandler from './EventHandler';
4+
import fuzzymatch from '../../utils/fuzzymatch';
35
import Action from './Action';
46
import Component from '../Component';
7+
import list from '../../utils/list';
58
import TemplateScope from './shared/TemplateScope';
69
import { Element } from '../../interfaces';
710
import compiler_warnings from '../compiler_warnings';
11+
import compiler_errors from '../compiler_errors';
12+
13+
const valid_bindings = [
14+
'fullscreenElement',
15+
'visibilityState'
16+
];
817

918
export default class Document extends Node {
1019
type: 'Document';
1120
handlers: EventHandler[] = [];
21+
bindings: Binding[] = [];
1222
actions: Action[] = [];
1323

1424
constructor(component: Component, parent: Node, scope: TemplateScope, info: Element) {
@@ -17,6 +27,17 @@ export default class Document extends Node {
1727
info.attributes.forEach((node) => {
1828
if (node.type === 'EventHandler') {
1929
this.handlers.push(new EventHandler(component, this, scope, node));
30+
} else if (node.type === 'Binding') {
31+
if (!~valid_bindings.indexOf(node.name)) {
32+
const match = fuzzymatch(node.name, valid_bindings);
33+
if (match) {
34+
return component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:document>', ` (did you mean '${match}'?)`));
35+
} else {
36+
return component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:document>', ` — valid bindings are ${list(valid_bindings)}`));
37+
}
38+
}
39+
40+
this.bindings.push(new Binding(component, this, scope, node));
2041
} else if (node.type === 'Action') {
2142
this.actions.push(new Action(component, this, scope, node));
2243
} else {

src/compiler/compile/nodes/Element.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { Literal } from 'estree';
2626
import compiler_warnings from '../compiler_warnings';
2727
import compiler_errors from '../compiler_errors';
2828
import { ARIARoleDefinitionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query';
29-
import { is_interactive_element, is_non_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader, is_semantic_role_element, is_abstract_role, is_static_element, has_disabled_attribute } from '../utils/a11y';
29+
import { is_interactive_element, is_non_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader, is_semantic_role_element, is_abstract_role, is_static_element, has_disabled_attribute, is_valid_autocomplete } from '../utils/a11y';
3030

3131
const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
3232
const aria_attribute_set = new Set(aria_attributes);
@@ -131,6 +131,7 @@ const a11y_implicit_semantics = new Map([
131131
['details', 'group'],
132132
['dt', 'term'],
133133
['fieldset', 'group'],
134+
['figure', 'figure'],
134135
['form', 'form'],
135136
['h1', 'heading'],
136137
['h2', 'heading'],
@@ -142,6 +143,7 @@ const a11y_implicit_semantics = new Map([
142143
['img', 'img'],
143144
['li', 'listitem'],
144145
['link', 'link'],
146+
['main', 'main'],
145147
['menu', 'list'],
146148
['meter', 'progressbar'],
147149
['nav', 'navigation'],
@@ -152,6 +154,7 @@ const a11y_implicit_semantics = new Map([
152154
['progress', 'progressbar'],
153155
['section', 'region'],
154156
['summary', 'button'],
157+
['table', 'table'],
155158
['tbody', 'rowgroup'],
156159
['textarea', 'textbox'],
157160
['tfoot', 'rowgroup'],
@@ -660,9 +663,7 @@ export default class Element extends Node {
660663
}
661664

662665
// no-redundant-roles
663-
const has_redundant_role = current_role === get_implicit_role(this.name, attribute_map);
664-
665-
if (this.name === current_role || has_redundant_role) {
666+
if (current_role === get_implicit_role(this.name, attribute_map)) {
666667
component.warn(attribute, compiler_warnings.a11y_no_redundant_roles(current_role));
667668
}
668669

@@ -918,6 +919,18 @@ export default class Element extends Node {
918919
should_have_attribute(this, required_attributes, 'input type="image"');
919920
}
920921
}
922+
923+
// autocomplete-valid
924+
const autocomplete = attribute_map.get('autocomplete');
925+
926+
if (type && autocomplete) {
927+
const type_value = type.get_static_value();
928+
const autocomplete_value = autocomplete.get_static_value();
929+
930+
if (!is_valid_autocomplete(type_value, autocomplete_value)) {
931+
component.warn(autocomplete, compiler_warnings.a11y_autocomplete_valid(type_value, autocomplete_value));
932+
}
933+
}
921934
}
922935

923936
if (this.name === 'img') {

src/compiler/compile/nodes/Window.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const valid_bindings = [
1717
'outerHeight',
1818
'scrollX',
1919
'scrollY',
20+
'devicePixelRatio',
2021
'online'
2122
];
2223

0 commit comments

Comments
 (0)