Skip to content

Commit f97dbca

Browse files
committed
Merge branch 'main' into snippet-types
2 parents 63f82c9 + 3eef1cb commit f97dbca

File tree

163 files changed

+3177
-2994
lines changed

Some content is hidden

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

163 files changed

+3177
-2994
lines changed

.changeset/beige-cobras-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
feat: add support for webkitdirectory DOM boolean attribute

.changeset/dull-pots-add.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: don't override instance methods during legacy class creation

.changeset/mighty-cooks-scream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: adjust scope parent for named slots

.changeset/olive-mice-fix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: improve handling of unowned derived signals

.changeset/pre.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"afraid-moose-matter",
1414
"angry-books-jam",
1515
"angry-plums-punch",
16+
"beige-cobras-smoke",
1617
"beige-flies-wash",
1718
"beige-mirrors-listen",
1819
"beige-rabbits-shave",
@@ -63,6 +64,7 @@
6364
"dry-eggs-retire",
6465
"dull-coins-vanish",
6566
"dull-mangos-wave",
67+
"dull-pots-add",
6668
"dull-roses-relate",
6769
"early-ads-tie",
6870
"eight-steaks-shout",
@@ -166,6 +168,7 @@
166168
"lucky-schools-hang",
167169
"lucky-toes-begin",
168170
"many-trees-fix",
171+
"mighty-cooks-scream",
169172
"mighty-files-hammer",
170173
"moody-carrots-lay",
171174
"moody-frogs-exist",
@@ -192,6 +195,7 @@
192195
"old-mails-sneeze",
193196
"old-oranges-compete",
194197
"olive-kangaroos-brake",
198+
"olive-mice-fix",
195199
"olive-seals-sell",
196200
"olive-shirts-complain",
197201
"olive-socks-kick",
@@ -233,6 +237,7 @@
233237
"rotten-rules-invite",
234238
"rude-ghosts-tickle",
235239
"selfish-dragons-knock",
240+
"selfish-spies-help",
236241
"selfish-tools-hide",
237242
"serious-kids-deliver",
238243
"serious-needles-joke",
@@ -265,6 +270,7 @@
265270
"small-papayas-laugh",
266271
"small-sheep-type",
267272
"smart-parents-swim",
273+
"smart-turkeys-tell",
268274
"smart-zebras-pay",
269275
"smooth-rings-rush",
270276
"soft-clocks-remember",
@@ -306,6 +312,7 @@
306312
"tasty-cheetahs-appear",
307313
"tasty-numbers-perform",
308314
"tasty-steaks-smile",
315+
"ten-eels-move",
309316
"ten-foxes-repeat",
310317
"ten-jokes-divide",
311318
"ten-peaches-sleep",

.changeset/selfish-spies-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: improve element class attribute behaviour

.changeset/silly-ways-wash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
feat: take form resets into account for two way bindings

.changeset/small-spiders-fail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
breaking: apply fallback value every time in runes mode

.changeset/smart-turkeys-tell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: ensure select value is updated upon select option removal

packages/svelte/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
/motion.d.ts
1212
/store.d.ts
1313
/transition.d.ts
14+
15+
/scripts/_bundle.js

packages/svelte/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# svelte
22

3+
## 5.0.0-next.81
4+
5+
### Patch Changes
6+
7+
- feat: add support for webkitdirectory DOM boolean attribute ([#10847](https://github.com/sveltejs/svelte/pull/10847))
8+
9+
- fix: don't override instance methods during legacy class creation ([#10834](https://github.com/sveltejs/svelte/pull/10834))
10+
11+
- fix: adjust scope parent for named slots ([#10843](https://github.com/sveltejs/svelte/pull/10843))
12+
13+
- fix: improve handling of unowned derived signals ([#10842](https://github.com/sveltejs/svelte/pull/10842))
14+
15+
- fix: improve element class attribute behaviour ([#10856](https://github.com/sveltejs/svelte/pull/10856))
16+
17+
- fix: ensure select value is updated upon select option removal ([#10846](https://github.com/sveltejs/svelte/pull/10846))
18+
19+
- fix: ensure capture events don't call delegated events ([#10831](https://github.com/sveltejs/svelte/pull/10831))
20+
321
## 5.0.0-next.80
422

523
### Patch Changes

packages/svelte/elements.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,7 @@ export interface HTMLInputAttributes extends HTMLAttributes<HTMLInputElement> {
10561056
type?: HTMLInputTypeAttribute | undefined | null;
10571057
value?: any;
10581058
width?: number | string | undefined | null;
1059+
webkitdirectory?: boolean | undefined | null;
10591060

10601061
'on:change'?: ChangeEventHandler<HTMLInputElement> | undefined | null;
10611062
onchange?: ChangeEventHandler<HTMLInputElement> | undefined | null;

packages/svelte/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "svelte",
33
"description": "Cybernetically enhanced web apps",
44
"license": "MIT",
5-
"version": "5.0.0-next.80",
5+
"version": "5.0.0-next.81",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

packages/svelte/scripts/check-treeshakeability.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ async function bundle_code(entry) {
1212
virtual({
1313
__entry__: entry
1414
}),
15+
{
16+
name: 'resolve-svelte',
17+
resolveId(importee) {
18+
if (importee.startsWith('svelte')) {
19+
const entry = pkg.exports[importee.replace('svelte', '.')];
20+
return path.resolve(entry.browser ?? entry.default);
21+
}
22+
}
23+
},
1524
nodeResolve({
1625
exportConditions: ['production', 'import', 'browser', 'default']
1726
})
@@ -65,7 +74,7 @@ for (const key in pkg.exports) {
6574
}
6675

6776
const client_main = path.resolve(pkg.exports['.'].browser);
68-
const without_hydration = await bundle_code(
77+
const bundle = await bundle_code(
6978
// Use all features which contain hydration code to ensure it's treeshakeable
7079
compile(
7180
`
@@ -99,15 +108,18 @@ const without_hydration = await bundle_code(
99108
{ filename: 'App.svelte' }
100109
).js.code
101110
);
102-
if (!without_hydration.includes('current_hydration_fragment')) {
111+
112+
if (!bundle.includes('current_hydration_fragment')) {
103113
// eslint-disable-next-line no-console
104114
console.error(`✅ Hydration code treeshakeable`);
105115
} else {
106116
// eslint-disable-next-line no-console
107-
console.error(without_hydration);
117+
console.error(bundle);
108118
// eslint-disable-next-line no-console
109119
console.error(`❌ Hydration code not treeshakeable`);
110120
failed = true;
121+
122+
fs.writeFileSync('scripts/_bundle.js', bundle);
111123
}
112124

113125
// eslint-disable-next-line no-console

packages/svelte/src/compiler/errors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ const runes = {
182182
`$props() assignment must not contain nested properties or computed keys`,
183183
'invalid-props-location': () =>
184184
`$props() can only be used at the top level of components as a variable declaration initializer`,
185+
'invalid-bindable-location': () => `$bindable() can only be used inside a $props() declaration`,
185186
/** @param {string} rune */
186187
'invalid-state-location': (rune) =>
187188
`${rune}(...) can only be used as a variable declaration initializer or a class field`,

packages/svelte/src/compiler/phases/2-analyze/index.js

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ export function analyze_component(root, options) {
436436
);
437437
}
438438
} else {
439-
instance.scope.declare(b.id('$$props'), 'prop', 'synthetic');
439+
instance.scope.declare(b.id('$$props'), 'bindable_prop', 'synthetic');
440440
instance.scope.declare(b.id('$$restProps'), 'rest_prop', 'synthetic');
441441

442442
for (const { ast, scope, scopes } of [module, instance, template]) {
@@ -466,7 +466,10 @@ export function analyze_component(root, options) {
466466
}
467467

468468
for (const [name, binding] of instance.scope.declarations) {
469-
if (binding.kind === 'prop' && binding.node.name !== '$$props') {
469+
if (
470+
(binding.kind === 'prop' || binding.kind === 'bindable_prop') &&
471+
binding.node.name !== '$$props'
472+
) {
470473
const references = binding.references.filter(
471474
(r) => r.node !== binding.node && r.path.at(-1)?.type !== 'ExportSpecifier'
472475
);
@@ -753,12 +756,13 @@ const legacy_scope_tweaker = {
753756
state.scope.get(specifier.local.name)
754757
);
755758
if (
756-
binding.kind === 'state' ||
757-
binding.kind === 'frozen_state' ||
758-
(binding.kind === 'normal' &&
759-
(binding.declaration_kind === 'let' || binding.declaration_kind === 'var'))
759+
binding !== null &&
760+
(binding.kind === 'state' ||
761+
binding.kind === 'frozen_state' ||
762+
(binding.kind === 'normal' &&
763+
(binding.declaration_kind === 'let' || binding.declaration_kind === 'var')))
760764
) {
761-
binding.kind = 'prop';
765+
binding.kind = 'bindable_prop';
762766
if (specifier.exported.name !== specifier.local.name) {
763767
binding.prop_alias = specifier.exported.name;
764768
}
@@ -796,7 +800,7 @@ const legacy_scope_tweaker = {
796800
for (const declarator of node.declaration.declarations) {
797801
for (const id of extract_identifiers(declarator.id)) {
798802
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name));
799-
binding.kind = 'prop';
803+
binding.kind = 'bindable_prop';
800804
}
801805
}
802806
}
@@ -885,11 +889,24 @@ const runes_scope_tweaker = {
885889
property.key.type === 'Identifier'
886890
? property.key.name
887891
: /** @type {string} */ (/** @type {import('estree').Literal} */ (property.key).value);
888-
const initial = property.value.type === 'AssignmentPattern' ? property.value.right : null;
892+
let initial = property.value.type === 'AssignmentPattern' ? property.value.right : null;
889893

890894
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(name));
891895
binding.prop_alias = alias;
892-
binding.initial = initial; // rewire initial from $props() to the actual initial value
896+
897+
// rewire initial from $props() to the actual initial value, stripping $bindable() if necessary
898+
if (
899+
initial?.type === 'CallExpression' &&
900+
initial.callee.type === 'Identifier' &&
901+
initial.callee.name === '$bindable'
902+
) {
903+
binding.initial = /** @type {import('estree').Expression | null} */ (
904+
initial.arguments[0] ?? null
905+
);
906+
binding.kind = 'bindable_prop';
907+
} else {
908+
binding.initial = initial;
909+
}
893910
}
894911
}
895912
},
@@ -1072,6 +1089,7 @@ const common_visitors = {
10721089
}
10731090

10741091
if (
1092+
context.state.analysis.runes &&
10751093
node !== binding.node &&
10761094
// If we have $state that can be proxied or frozen and isn't re-assigned, then that means
10771095
// it's likely not using a primitive value and thus this warning isn't that helpful.

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,17 +299,19 @@ const validation = {
299299
error(node, 'invalid-binding-expression');
300300
}
301301

302+
const binding = context.state.scope.get(left.name);
303+
302304
if (
303305
assignee.type === 'Identifier' &&
304306
node.name !== 'this' // bind:this also works for regular variables
305307
) {
306-
const binding = context.state.scope.get(left.name);
307308
// reassignment
308309
if (
309310
!binding ||
310311
(binding.kind !== 'state' &&
311312
binding.kind !== 'frozen_state' &&
312313
binding.kind !== 'prop' &&
314+
binding.kind !== 'bindable_prop' &&
313315
binding.kind !== 'each' &&
314316
binding.kind !== 'store_sub' &&
315317
!binding.mutated)
@@ -328,8 +330,6 @@ const validation = {
328330
// TODO handle mutations of non-state/props in runes mode
329331
}
330332

331-
const binding = context.state.scope.get(left.name);
332-
333333
if (node.name === 'group') {
334334
if (!binding) {
335335
error(node, 'INTERNAL', 'Cannot find declaration for bind:group');
@@ -780,7 +780,25 @@ function validate_call_expression(node, scope, path) {
780780
error(node, 'invalid-props-location');
781781
}
782782

783-
if (rune === '$state' || rune === '$derived' || rune === '$derived.by') {
783+
if (rune === '$bindable') {
784+
if (parent.type === 'AssignmentPattern' && path.at(-3)?.type === 'ObjectPattern') {
785+
const declarator = path.at(-4);
786+
if (
787+
declarator?.type === 'VariableDeclarator' &&
788+
get_rune(declarator.init, scope) === '$props'
789+
) {
790+
return;
791+
}
792+
}
793+
error(node, 'invalid-bindable-location');
794+
}
795+
796+
if (
797+
rune === '$state' ||
798+
rune === '$state.frozen' ||
799+
rune === '$derived' ||
800+
rune === '$derived.by'
801+
) {
784802
if (parent.type === 'VariableDeclarator') return;
785803
if (parent.type === 'PropertyDefinition' && !parent.static && !parent.computed) return;
786804
error(node, 'invalid-state-location', rune);
@@ -873,6 +891,8 @@ export const validation_runes_js = {
873891
error(node, 'invalid-rune-args-length', rune, [0, 1]);
874892
} else if (rune === '$props') {
875893
error(node, 'invalid-props-location');
894+
} else if (rune === '$bindable') {
895+
error(node, 'invalid-bindable-location');
876896
}
877897
},
878898
AssignmentExpression(node, { state }) {
@@ -1022,6 +1042,9 @@ export const validation_runes = merge(validation, a11y_validators, {
10221042
}
10231043
},
10241044
CallExpression(node, { state, path }) {
1045+
if (get_rune(node, state.scope) === '$bindable' && node.arguments.length > 1) {
1046+
error(node, 'invalid-rune-args-length', '$bindable', [0, 1]);
1047+
}
10251048
validate_call_expression(node, state.scope, path);
10261049
},
10271050
EachBlock(node, { next, state }) {
@@ -1062,7 +1085,7 @@ export const validation_runes = merge(validation, a11y_validators, {
10621085
state.has_props_rune = true;
10631086

10641087
if (args.length > 0) {
1065-
error(node, 'invalid-rune-args-length', '$props', [0]);
1088+
error(node, 'invalid-rune-args-length', rune, [0]);
10661089
}
10671090

10681091
if (node.id.type !== 'ObjectPattern') {

0 commit comments

Comments
 (0)