@ -27,22 +27,17 @@ import {
get ,
is _signal ,
push _destroy _fn ,
set ,
execute _effect ,
UNINITIALIZED ,
derived ,
untrack ,
effect ,
flushSync ,
safe _not _equal ,
current _block ,
source ,
managed _effect ,
push ,
current _component _context ,
pop ,
unwrap ,
mutable _source
pop
} from './runtime.js' ;
import {
current _hydration _fragment ,
@ -56,12 +51,13 @@ import {
get _descriptor ,
get _descriptors ,
is _array ,
is _function ,
object _assign ,
object _entries ,
object _keys
} from './utils.js' ;
import { is _promise } from '../common.js' ;
import { bind _transition , trigger _transitions } from './transitions.js' ;
import { proxy } from './proxy/proxy.js' ;
/** @type {Set<string>} */
const all _registerd _events = new Set ( ) ;
@ -227,7 +223,7 @@ export function close_frag(anchor, dom) {
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < ( event : Event , ... args : Array < unknown > ) => void > } fn
* @ param { ( event : Event , ... args : Array < unknown > ) => void } fn
* @ returns { ( event : Event , ... args : unknown [ ] ) => void }
* /
export function trusted ( fn ) {
@ -235,13 +231,13 @@ export function trusted(fn) {
const event = /** @type {Event} */ ( args [ 0 ] ) ;
if ( event . isTrusted ) {
// @ts-ignore
unwrap( fn) . apply ( this , args ) ;
fn. apply ( this , args ) ;
}
} ;
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < ( event : Event , ... args : Array < unknown > ) => void > } fn
* @ param { ( event : Event , ... args : Array < unknown > ) => void } fn
* @ returns { ( event : Event , ... args : unknown [ ] ) => void }
* /
export function self ( fn ) {
@ -250,13 +246,13 @@ export function self(fn) {
// @ts-ignore
if ( event . target === this ) {
// @ts-ignore
unwrap( fn) . apply ( this , args ) ;
fn. apply ( this , args ) ;
}
} ;
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < ( event : Event , ... args : Array < unknown > ) => void > } fn
* @ param { ( event : Event , ... args : Array < unknown > ) => void } fn
* @ returns { ( event : Event , ... args : unknown [ ] ) => void }
* /
export function stopPropagation ( fn ) {
@ -264,12 +260,12 @@ export function stopPropagation(fn) {
const event = /** @type {Event} */ ( args [ 0 ] ) ;
event . stopPropagation ( ) ;
// @ts-ignore
return unwrap( fn) . apply ( this , args ) ;
return fn. apply ( this , args ) ;
} ;
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < ( event : Event , ... args : Array < unknown > ) => void > } fn
* @ param { ( event : Event , ... args : Array < unknown > ) => void } fn
* @ returns { ( event : Event , ... args : unknown [ ] ) => void }
* /
export function once ( fn ) {
@ -280,12 +276,12 @@ export function once(fn) {
}
ran = true ;
// @ts-ignore
return unwrap( fn) . apply ( this , args ) ;
return fn. apply ( this , args ) ;
} ;
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < ( event : Event , ... args : Array < unknown > ) => void > } fn
* @ param { ( event : Event , ... args : Array < unknown > ) => void } fn
* @ returns { ( event : Event , ... args : unknown [ ] ) => void }
* /
export function stopImmediatePropagation ( fn ) {
@ -293,12 +289,12 @@ export function stopImmediatePropagation(fn) {
const event = /** @type {Event} */ ( args [ 0 ] ) ;
event . stopImmediatePropagation ( ) ;
// @ts-ignore
return unwrap( fn) . apply ( this , args ) ;
return fn. apply ( this , args ) ;
} ;
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < ( event : Event , ... args : Array < unknown > ) => void > } fn
* @ param { ( event : Event , ... args : Array < unknown > ) => void } fn
* @ returns { ( event : Event , ... args : unknown [ ] ) => void }
* /
export function preventDefault ( fn ) {
@ -306,7 +302,7 @@ export function preventDefault(fn) {
const event = /** @type {Event} */ ( args [ 0 ] ) ;
event . preventDefault ( ) ;
// @ts-ignore
return unwrap( fn) . apply ( this , args ) ;
return fn. apply ( this , args ) ;
} ;
}
@ -1188,27 +1184,25 @@ export function bind_property(property, event_name, type, dom, get_value, update
}
} ) ;
}
/ * *
* Makes an ` export ` ed ( non - prop ) variable available on the ` $ $ props ` object
* so that consumers can do ` bind:x ` on the component .
* @ template V
* @ param { import ( './types.js' ) . MaybeSignal < Record < string , unknown > >} props
* @ param { Record < string , unknown >} props
* @ param { string } prop
* @ param { V } value
* @ returns { void }
* /
export function bind _prop ( props , prop , value ) {
/** @param {V | null} value */
const update = ( value ) => {
const current _props = unwrap ( props ) ;
if ( get _descriptor ( current _props , prop ) ? . set !== undefined ) {
current _props [ prop ] = value ;
}
} ;
update ( value ) ;
render _effect ( ( ) => ( ) => {
update ( null ) ;
} ) ;
const desc = get _descriptor ( props , prop ) ;
if ( desc && desc . set ) {
props [ prop ] = value ;
render _effect ( ( ) => ( ) => {
props [ prop ] = null ;
} ) ;
}
}
/ * *
@ -2531,68 +2525,98 @@ export function spread_dynamic_element_attributes(node, prev, attrs, css_hash) {
}
/ * *
* @ param { import ( './types.js' ) . Signal < Record < string , unknown >> | Record < string , unknown > } props _signal
* @ param { string [ ] } rest
* @ returns { Record < string , unknown > }
* The proxy handler for rest props ( i . e . ` const { x, ...rest } = $ props() ` ) .
* Is passed the full ` $ $ props ` object and excludes the named props .
* @ type { ProxyHandler < { props : Record < string | symbol , unknown > , exclude : Array < string | symbol > } > } }
* /
export function rest _props ( props _signal , rest ) {
return derived ( ( ) => {
var props = unwrap ( props _signal ) ;
/** @type {Record<string, unknown>} */
var rest _props = { } ;
for ( var key in props ) {
if ( rest . includes ( key ) ) continue ;
const { get , value , enumerable } = /** @type {PropertyDescriptor} */ (
get _descriptor ( props , key )
) ;
const rest _props _handler = {
get ( target , key ) {
if ( target . exclude . includes ( key ) ) return ;
return target . props [ key ] ;
} ,
getOwnPropertyDescriptor ( target , key ) {
if ( target . exclude . includes ( key ) ) return ;
if ( key in target . props ) {
return {
enumerable : true ,
configurable : true ,
value : target . props [ key ]
} ;
}
} ,
has ( target , key ) {
if ( target . exclude . includes ( key ) ) return false ;
return key in target . props ;
} ,
ownKeys ( target ) {
/** @type {Array<string | symbol>} */
const keys = [ ] ;
define _property ( rest _props , key , get ? { get , enumerable } : { value , enumerable } ) ;
for ( let key in target . props ) {
if ( ! target . exclude . includes ( key ) ) keys . push ( key ) ;
}
return rest _props ;
} ) ;
}
return key s;
}
} ;
/ * *
* @ param { Record < string , unknown > [ ] | ( ( ) => Record < string , unknown > [ ] ) } props
* @ returns { any }
* @ param { import ( './types.js' ) . Signal < Record < string , unknown >> | Record < string , unknown > } props
* @ param { string [ ] } rest
* @ returns { Record < string , unknown > }
* /
export function spread _props ( props ) {
if ( typeof props === 'function' ) {
return derived ( ( ) => {
return spread _props ( props ( ) ) ;
} ) ;
}
/** @type {Record<string, unknown>} */
const merged _props = { } ;
let key ;
for ( let i = 0 ; i < props . length ; i ++ ) {
const obj = props [ i ] ;
for ( key in obj ) {
const desc = /** @type {PropertyDescriptor} */ ( get _descriptor ( obj , key ) ) ;
const getter = desc . get ;
if ( getter !== undefined ) {
define _property ( merged _props , key , {
enumerable : true ,
configurable : true ,
get : getter
} ) ;
} else if ( desc . get !== undefined ) {
merged _props [ key ] = obj [ key ] ;
} else {
define _property ( merged _props , key , {
enumerable : true ,
configurable : true ,
value : obj [ key ]
} ) ;
export function rest _props ( props , rest ) {
return new Proxy ( { props , exclude : rest } , rest _props _handler ) ;
}
/ * *
* The proxy handler for spread props . Handles the incoming array of props
* that looks like ` () => { dynamic: props }, { static: prop }, .. ` and wraps
* them so that the whole thing is passed to the component as the ` $ $ props ` argument .
* @ template { Record < string | symbol , unknown > } T
* @ type { ProxyHandler < { props : Array < T | ( ( ) => T ) > } > } }
* /
const spread _props _handler = {
get ( target , key ) {
let i = target . props . length ;
while ( i -- ) {
let p = target . props [ i ] ;
if ( is _function ( p ) ) p = p ( ) ;
if ( typeof p === 'object' && p !== null && key in p ) return p [ key ] ;
}
} ,
getOwnPropertyDescriptor ( ) {
return { enumerable : true , configurable : true } ;
} ,
has ( target , key ) {
for ( let p of target . props ) {
if ( is _function ( p ) ) p = p ( ) ;
if ( key in p ) return true ;
}
return false ;
} ,
ownKeys ( target ) {
/** @type {Array<string | symbol>} */
const keys = [ ] ;
for ( let p of target . props ) {
if ( is _function ( p ) ) p = p ( ) ;
for ( const key in p ) {
if ( ! keys . includes ( key ) ) keys . push ( key ) ;
}
}
return keys ;
}
return merged _props ;
} ;
/ * *
* @ param { Array < Record < string , unknown > | ( ( ) => Record < string , unknown > ) > } props
* @ returns { any }
* /
export function spread _props ( ... props ) {
return new Proxy ( { props } , spread _props _handler ) ;
}
/ * *
@ -2616,73 +2640,14 @@ export function spread_props(props) {
* @ returns { Exports & { $destroy : ( ) => void ; $set : ( props : Partial < Props > ) => void ; } }
* /
export function createRoot ( component , options ) {
// The following definitions aren't duplicative. We need _sources to update single props and
// _props in case the component uses $$props / $$restProps / const { x, ...rest } = $props().
/** @type {any} */
const _props = { } ;
/** @type {any} */
const _sources = { } ;
/ * *
* @ param { string } name
* @ param { any } value
* /
function add _prop ( name , value ) {
const prop = source ( value ) ;
_sources [ name ] = prop ;
define _property ( _props , name , {
get ( ) {
return get ( prop ) ;
} ,
enumerable : true
} ) ;
}
const props = proxy ( /** @type {any} */ ( options . props ) || { } , false ) ;
for ( const prop in options . props || { } ) {
add _prop (
prop ,
// @ts-expect-error TS doesn't understand this properly
options . props [ prop ]
) ;
}
// The proxy ensures that we can add new signals on the fly when a prop signal is accessed from within the component
// but no corresponding prop value was set from the outside. The whole things becomes a _propsSignal
// so that adding new props is reflected in the component if it uses $$props or $$restProps.
const props _proxy = new Proxy ( _props , {
/ * *
* @ param { any } target
* @ param { any } property
* /
get : ( target , property ) => {
if ( typeof property !== 'string' ) return target [ property ] ;
if ( ! ( property in _sources ) ) {
add _prop ( property , undefined ) ;
}
return _props [ property ] ;
}
} ) ;
// We're resetting the same proxy instance for updates, therefore bypass equality checks
const props _source = mutable _source ( props _proxy ) ;
let [ accessors , $destroy ] = mount ( component , {
... options ,
// @ts-expect-error We hide the "the props object could be a signal" fact from the public typings
props : props _source
} ) ;
let [ accessors , $destroy ] = mount ( component , { ... options , props } ) ;
const result =
/** @type {Exports & { $destroy: () => void; $set: (props: Partial<Props>) => void; }} */ ( {
$set : ( props ) => {
for ( const [ prop , value ] of object _entries ( props ) ) {
if ( prop in _sources ) {
set ( _sources [ prop ] , value ) ;
} else {
add _prop ( prop , value ) ;
set ( props _source , props _proxy ) ;
}
}
$set : ( next ) => {
object _assign ( props , next ) ;
} ,
$destroy
} ) ;
@ -2837,11 +2802,10 @@ export function access_props(props) {
}
/ * *
* @ param { import ( './types.js' ) . MaybeSignal < Record < string , any > >} props
* @ param { Record < string , any >} props
* @ returns { Record < string , any > }
* /
export function sanitize _slots ( props ) {
props = unwrap ( props ) ;
const sanitized = { ... props . $$slots } ;
if ( props . children ) sanitized . default = props . children ;
return sanitized ;