diff --git a/packages/svelte/src/internal/client/constants.js b/packages/svelte/src/internal/client/constants.js index 53df86126a..bcf30e78db 100644 --- a/packages/svelte/src/internal/client/constants.js +++ b/packages/svelte/src/internal/client/constants.js @@ -22,4 +22,5 @@ export const EFFECT_HAS_DERIVED = 1 << 19; export const STATE_SYMBOL = Symbol('$state'); export const STATE_SYMBOL_METADATA = Symbol('$state metadata'); +export const LEGACY_PROPS = Symbol('legacy props'); export const LOADING_ATTR_SYMBOL = Symbol(''); diff --git a/packages/svelte/src/internal/client/reactivity/props.js b/packages/svelte/src/internal/client/reactivity/props.js index 527a99e25d..379b9c3c29 100644 --- a/packages/svelte/src/internal/client/reactivity/props.js +++ b/packages/svelte/src/internal/client/reactivity/props.js @@ -20,7 +20,13 @@ import { } from '../runtime.js'; import { safe_equals } from './equality.js'; import * as e from '../errors.js'; -import { BRANCH_EFFECT, LEGACY_DERIVED_PROP, ROOT_EFFECT, STATE_SYMBOL } from '../constants.js'; +import { + BRANCH_EFFECT, + LEGACY_DERIVED_PROP, + LEGACY_PROPS, + ROOT_EFFECT, + STATE_SYMBOL +} from '../constants.js'; import { proxy } from '../proxy.js'; import { capture_store_binding } from './store.js'; import { legacy_mode_flag } from '../../flags/index.js'; @@ -283,10 +289,12 @@ export function prop(props, key, flags, fallback) { prop_value = /** @type {V} */ (props[key]); } + // Can be the case when someone does `mount(Component, props)` with `let props = $state({...})` + // or `createClassComponent(Component, props)` + var is_entry_props = STATE_SYMBOL in props || LEGACY_PROPS in props; + var setter = - get_descriptor(props, key)?.set ?? - // Can be the case when someone does `mount(Component, props)` with `let props = $state({...})` - (STATE_SYMBOL in props ? (v) => (props[key] = v) : undefined); + get_descriptor(props, key)?.set ?? (is_entry_props ? (v) => (props[key] = v) : undefined); var fallback_value = /** @type {V} */ (fallback); var fallback_dirty = true; @@ -307,7 +315,7 @@ export function prop(props, key, flags, fallback) { }; if (prop_value === undefined && fallback !== undefined) { - if (setter && runes) { + if (setter && runes && !is_entry_props) { e.props_invalid_value(key); } diff --git a/packages/svelte/src/internal/client/validate.js b/packages/svelte/src/internal/client/validate.js index eddcb69d9e..951feee33b 100644 --- a/packages/svelte/src/internal/client/validate.js +++ b/packages/svelte/src/internal/client/validate.js @@ -1,4 +1,4 @@ -import { dev_current_component_function, untrack } from './runtime.js'; +import { dev_current_component_function } from './runtime.js'; import { get_descriptor, is_array } from '../shared/utils.js'; import * as e from './errors.js'; import { FILENAME } from '../../constants.js'; @@ -6,15 +6,6 @@ import { render_effect } from './reactivity/effects.js'; import * as w from './warnings.js'; import { capture_store_binding } from './reactivity/store.js'; -/** regex of all html void element names */ -const void_element_names = - /^(?:area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/; - -/** @param {string} tag */ -function is_void(tag) { - return void_element_names.test(tag) || tag.toLowerCase() === '!doctype'; -} - /** * @param {() => any} collection * @param {(item: any, index: number) => string} key_fn diff --git a/packages/svelte/src/legacy/legacy-client.js b/packages/svelte/src/legacy/legacy-client.js index 30f2161b77..9e1cd888ad 100644 --- a/packages/svelte/src/legacy/legacy-client.js +++ b/packages/svelte/src/legacy/legacy-client.js @@ -1,5 +1,5 @@ /** @import { ComponentConstructorOptions, ComponentType, SvelteComponent, Component } from 'svelte' */ -import { DIRTY, MAYBE_DIRTY } from '../internal/client/constants.js'; +import { DIRTY, LEGACY_PROPS, MAYBE_DIRTY } from '../internal/client/constants.js'; import { user_pre_effect } from '../internal/client/reactivity/effects.js'; import { mutable_source, set } from '../internal/client/reactivity/sources.js'; import { hydrate, mount, unmount } from '../internal/client/render.js'; @@ -89,7 +89,7 @@ class Svelte4Component { }; // Replicate coarse-grained props through a proxy that has a version source for - // each property, which is increment on updates to the property itself. Do not + // each property, which is incremented on updates to the property itself. Do not // use our $state proxy because that one has fine-grained reactivity. const props = new Proxy( { ...(options.props || {}), $$events: {} }, @@ -98,26 +98,15 @@ class Svelte4Component { return get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))); }, has(target, prop) { + // Necessary to not throw "invalid binding" validation errors on the component side + if (prop === LEGACY_PROPS) return true; + get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))); return Reflect.has(target, prop); }, set(target, prop, value) { set(sources.get(prop) ?? add_source(prop, value), value); return Reflect.set(target, prop, value); - }, - getOwnPropertyDescriptor(target, prop) { - // TODO this throws "invalid binding" errors on the component side - const desc = Reflect.getOwnPropertyDescriptor(target, prop); - if (!desc?.configurable) return desc; - return { - get: () => get(sources.get(prop) ?? add_source(prop, Reflect.get(target, prop))), - set: (value) => { - set(sources.get(prop) ?? add_source(prop, value), value); - return Reflect.set(target, prop, value); - }, - enumerable: desc.enumerable, - configurable: desc.configurable - }; } } );