11// Embrace some optimal ugly code, if it makes the minified code smaller.
22
33import type { StrictARIA } from "./aria.ts" ;
4- import { computed , Signal } from "./signals.ts" ;
4+ import { Signal } from "./signals.ts" ;
55import type { _Event , Equal , Extends , Fn , If , IsReadonly , Not } from "./utils.ts" ;
66import { instancesOf } from "./utils.ts" ;
77
@@ -136,7 +136,9 @@ type ProxyFunctionArgs<T extends Node, K extends keyof T, Args extends unknown[]
136136 : T extends WithLifecycle ? RecursiveSignalArgs < Args >
137137 : Args ;
138138
139- type MaybeNodeLikeArg < T > = T extends Node ? T | Builder < T > | null : T extends string ? string | { toString ( ) : string } : T ;
139+ type MaybeNodeLikeArg < T > = T extends Node ? T | Builder < T > | null | undefined
140+ : T extends string ? string | { toString ( ) : string } | null | undefined
141+ : T ;
140142type MaybeNodeLikeArgs < Args extends unknown [ ] , R extends unknown [ ] = [ ] > = Args extends [ infer Head , ...infer Tail ]
141143 ? MaybeNodeLikeArgs < Tail , [ ...R , MaybeNodeLikeArg < Head > ] >
142144 : Args extends ( infer U ) [ ] ? MaybeNodeLikeArg < U > [ ]
@@ -205,7 +207,7 @@ export let Builder: BuilderConstructor = function <T extends Node & Partial<With
205207 } ;
206208
207209 if ( instancesOf ( value , Signal ) ) {
208- node . $effect ! ( ( ) => value . follow ( setOrRemoveAttribute , true ) ) ;
210+ node . $bind ! ( ( ) => value . follow ( setOrRemoveAttribute , true ) ) ;
209211 } else {
210212 setOrRemoveAttribute ( value ) ;
211213 }
@@ -222,49 +224,14 @@ export let Builder: BuilderConstructor = function <T extends Node & Partial<With
222224 return target [ targetName ] ;
223225 }
224226
225- nodeName = ( targetName . at ( - 1 ) == "$" ? targetName . slice ( 0 , - 1 ) : targetName ) as keyof T & string ;
227+ nodeName = ( targetName . at ( - 1 ) == "$" ? ( targetName . slice ( 0 , - 1 ) ) : targetName ) as never ;
226228 fn = ( instancesOf ( node [ nodeName ] , Function ) && ! Object . hasOwn ( node , nodeName ) )
227- ? ( nodeName == targetName ) ? ( args : unknown [ ] ) => ( node [ nodeName ] as Fn ) ( ...args ) : ( (
228- args : unknown [ ] ,
229- computedArgs : Signal < unknown [ ] > ,
230- hasSignal : boolean | undefined ,
231- unwrap = ( value : unknown ) : string | Node | { toString ( ) : string } => {
232- if ( value == null ) {
233- return unwrap ( [ ] ) ;
234- }
235- if ( instancesOf ( value , Builder ) ) {
236- return value . $node ;
237- }
238- if ( instancesOf ( value , Signal ) ) {
239- hasSignal = true ;
240- return unwrap ( value . val ) ;
241- }
242- if ( instancesOf ( value , Array ) ) {
243- return unwrap ( new Builder ( document . createDocumentFragment ( ) ) . append ( ...value . map ( unwrap ) as never [ ] ) ) ;
244- }
245- return value ;
246- } ,
247- unwrappedArgs : unknown [ ] ,
248- ) => {
249- // This is the best i can come up with
250- // Normally if we had a persistent document fragment with lifecyle,
251- // we could have just wrapped signals with it in the DOM. Not doing these at all.
252- //
253- // I can wrap them with an element with lifecycle and give it `display:contents`,
254- // but that causes other issues in the dx
255- unwrappedArgs = args . map ( unwrap ) ;
256- if ( hasSignal ) {
257- computedArgs = computed ( ( ) => args . map ( unwrap ) ) ;
258- cleanups [ targetName ] = node . $effect ! ( ( ) =>
259- computedArgs . follow ( ( newArgs ) => ( node [ nodeName ] as Fn ) ( ...newArgs ) , true )
260- ) ;
261- } else {
262- ( node [ nodeName ] as Fn ) ( ...unwrappedArgs ) ;
263- }
264- } )
229+ ? ( nodeName == targetName )
230+ ? ( args : unknown [ ] ) => ( node [ nodeName ] as Fn ) ( ...args )
231+ : ( ( args : Member [ ] ) => ( node [ nodeName ] as Fn ) ( ...args . map ( toChild ) ) )
265232 : ( ( [ value ] : [ unknown ] ) => {
266233 if ( instancesOf ( value , Signal ) ) {
267- cleanups [ targetName ] = node . $effect ! ( ( ) => value . follow ( ( value ) => node [ nodeName ] = value as never , true ) ) ;
234+ cleanups [ targetName ] = node . $bind ! ( ( ) => value . follow ( ( value ) => node [ nodeName ] = value as never , true ) ) ;
268235 } else {
269236 node [ nodeName ] = value as never ;
270237 }
@@ -290,12 +257,12 @@ export namespace Lifecycle {
290257 export type OffConnected = ( ) => void ;
291258}
292259export type Lifecycle < T extends HTMLElement = HTMLElement > = {
293- $effect ( callback : Lifecycle . OnConnected < T > ) : Lifecycle . OffConnected ;
260+ $bind ( callback : Lifecycle . OnConnected < T > ) : Lifecycle . OffConnected ;
294261} ;
295262
296263export type WithLifecycle < T extends HTMLElement = HTMLElement > = T & Lifecycle < T > ;
297264
298- let withLifecycleCache = new Map < { new ( ) : HTMLElement } , { new ( ) : WithLifecycle < HTMLElement > } > ( ) ;
265+ let withLifecycleCache = new WeakMap < { new ( ) : HTMLElement } , { new ( ) : WithLifecycle < HTMLElement > } > ( ) ;
299266export let WithLifecycle = < BaseConstructor extends { new ( ...params : any [ ] ) : HTMLElement } > (
300267 Base : BaseConstructor ,
301268) : {
@@ -311,14 +278,14 @@ export let WithLifecycle = <BaseConstructor extends { new (...params: any[]): HT
311278 #callbacks = new Map < Lifecycle . OnConnected < Base > , ReturnType < Lifecycle . OnConnected < Base > > | null > ( ) ;
312279
313280 connectedCallback ( ) : void {
314- this . #callbacks. keys ( ) . forEach ( ( callback ) => this . #callbacks. set ( callback , callback ( this ) ) ) ;
281+ this . #callbacks. forEach ( ( _ , callback ) => this . #callbacks. set ( callback , callback ( this ) ) ) ;
315282 }
316283
317284 disconnectedCallback ( ) : void {
318285 this . #callbacks. forEach ( ( disconnectedCallbackOrNullish ) => disconnectedCallbackOrNullish ?.( ) ) ;
319286 }
320287
321- $effect ( callback : Lifecycle . OnConnected < Base > ) : Lifecycle . OffConnected {
288+ $bind ( callback : Lifecycle . OnConnected < Base > ) : Lifecycle . OffConnected {
322289 this . #callbacks. set ( callback , null ) ;
323290 return ( ) => {
324291 let off = this . #callbacks. get ( callback ) ;
@@ -332,3 +299,20 @@ export let WithLifecycle = <BaseConstructor extends { new (...params: any[]): HT
332299
333300 return constructor as never ;
334301} ;
302+
303+ export type Member = RecursiveSignalAndArrayOf < MaybeNodeLikeArg < Node | string > > ;
304+ let toChild = ( member : Member ) : string | Node => {
305+ if ( instancesOf ( member , Builder ) ) {
306+ return member . $node ;
307+ }
308+ if ( instancesOf ( member , Signal ) ) {
309+ return toChild (
310+ tags . div ( { style : "display:contents" } )
311+ . $bind ( ( element ) => member . follow ( ( value ) => element . replaceChildren ( toChild ( value ) ) , true ) ) ,
312+ ) ;
313+ }
314+ if ( instancesOf ( member , Array ) ) {
315+ return toChild ( new Builder ( document . createDocumentFragment ( ) ) . append ( ...member . map ( toChild ) as never [ ] ) ) ;
316+ }
317+ return ( member satisfies { toString ( ) : string } | null | undefined ) as string ;
318+ } ;
0 commit comments