@@ -4,6 +4,7 @@ const isString = isOfType('string');
4
4
const isObject = isOfType ( 'object' ) ;
5
5
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
6
6
const isFunction = isOfType ( 'function' ) ;
7
+ const isNull = ( value ) => value === null ;
7
8
const isNullish = ( value ) => value == null ;
8
9
const isDefined = ( value ) => value != null ;
9
10
const isDefinedObject = ( value ) => isDefined ( value ) && ( isObject ( value ) || isFunction ( value ) ) ;
@@ -266,7 +267,7 @@ const initContext = (host) => {
266
267
if ( ! provided . includes ( context ) || ! isFunction ( callback ) )
267
268
return ;
268
269
e . stopPropagation ( ) ;
269
- callback ( host . get ( String ( context ) ) ) ;
270
+ callback ( host . signal ( String ( context ) ) ) ;
270
271
} ) ;
271
272
} ;
272
273
@@ -338,7 +339,7 @@ const off = (event, handler) =>
338
339
*
339
340
* @since 0.8.3
340
341
* @param {string } event - event name to dispatch
341
- * @param {StateLike } state - state key
342
+ * @param {StateLike<unknown> } state - state key
342
343
*/
343
344
const emit = ( event , state = event ) =>
344
345
/**
@@ -414,19 +415,25 @@ const asJSON = (value) => {
414
415
*
415
416
* @since 0.8.0
416
417
* @param {UI } ui - UI object of host UIElement and target element to update properties
417
- * @param {StateLike } state - state to be set to the host element
418
+ * @param {StateLike<T> } state - state to be set to the host element
418
419
* @param {string } prop - property name to be updated
419
- * @param {T } fallback - fallback value to be used if state is not defined
420
- * @param {(element: E) => () => void } onNothing - callback to be executed when state is not defined
421
- * @param {(value: T) => (element: E) => () => void } onSomething - callback to be executed when state is defined
420
+ * @param {() => T } getter - getter function to retrieve current value in the DOM
421
+ * @param {(value: T) => (element: E) => () => void } setter - callback to be executed when state is changed
422
422
* @returns {UI } object with host and target
423
423
*/
424
- const autoEffect = ( ui , state , prop , fallback , onNothing , onSomething ) => {
424
+ const autoEffect = ( ui , state , prop , getter , setter , remover ) => {
425
+ const fallback = getter ( ) ;
425
426
if ( ! isFunction ( state ) )
426
427
ui . host . set ( state , isString ( state ) && isString ( fallback ) ? parse ( ui . host , state , fallback ) : fallback , false ) ;
427
428
effect ( ( enqueue ) => {
428
- const value = isFunction ( state ) ? state ( ) : ui . host . get ( state ) ;
429
- enqueue ( ui . target , prop , isNullish ( value ) ? onNothing : onSomething ( value ) ) ;
429
+ const current = getter ( ) ;
430
+ const value = isFunction ( state ) ? state ( current ) : ui . host . get ( state ) ;
431
+ if ( ! Object . is ( value , current ) )
432
+ enqueue ( ui . target , prop , remover && isNull ( value )
433
+ ? remover
434
+ : isNullish ( value )
435
+ ? setter ( fallback )
436
+ : setter ( value ) ) ;
430
437
} ) ;
431
438
return ui ;
432
439
} ;
@@ -435,64 +442,54 @@ const autoEffect = (ui, state, prop, fallback, onNothing, onSomething) => {
435
442
* Set text content of an element
436
443
*
437
444
* @since 0.8.0
438
- * @param {StateLike } state - state bounded to the text content
439
- */
440
- const setText = ( state ) => ( ui ) => {
441
- const fallback = ui . target . textContent || '' ;
442
- const setter = ( value ) => ( element ) => ( ) => {
443
- Array . from ( element . childNodes )
444
- . filter ( isComment )
445
- . forEach ( match => match . remove ( ) ) ;
446
- element . append ( document . createTextNode ( value ) ) ;
447
- } ;
448
- return autoEffect ( ui , state , 't' , fallback , setter ( fallback ) , setter ) ;
449
- } ;
445
+ * @param {StateLike<string> } state - state bounded to the text content
446
+ */
447
+ const setText = ( state ) => ( ui ) => autoEffect ( ui , state , 't' , ( ) => ui . target . textContent || '' , ( value ) => ( element ) => ( ) => {
448
+ Array . from ( element . childNodes )
449
+ . filter ( isComment )
450
+ . forEach ( match => match . remove ( ) ) ;
451
+ element . append ( document . createTextNode ( value ) ) ;
452
+ } ) ;
450
453
/**
451
454
* Set property of an element
452
455
*
453
456
* @since 0.8.0
454
457
* @param {PropertyKey } key - name of property to be set
455
- * @param {StateLike } state - state bounded to the property value
458
+ * @param {StateLike<unknown> } state - state bounded to the property value
456
459
*/
457
- const setProperty = ( key , state = key ) => ( ui ) => {
458
- const setter = ( value ) => ( element ) => ( ) => element [ key ] = value ;
459
- return autoEffect ( ui , state , `p-${ String ( key ) } ` , ui . target [ key ] , setter ( null ) , setter ) ;
460
- } ;
460
+ const setProperty = ( key , state = key ) => ( ui ) => autoEffect ( ui , state , `p-${ String ( key ) } ` , ( ) => ui . target [ key ] , ( value ) => ( element ) => ( ) => element [ key ] = value ) ;
461
461
/**
462
462
* Set attribute of an element
463
463
*
464
464
* @since 0.8.0
465
465
* @param {string } name - name of attribute to be set
466
- * @param {StateLike } state - state bounded to the attribute value
466
+ * @param {StateLike<string> } state - state bounded to the attribute value
467
467
*/
468
- const setAttribute = ( name , state = name ) => ( ui ) => autoEffect ( ui , state , `a-${ name } ` , ui . target . getAttribute ( name ) , ( element ) => ( ) => element . removeAttribute ( name ) , ( value ) => ( element ) => ( ) => element . setAttribute ( name , value ) ) ;
468
+ const setAttribute = ( name , state = name ) => ( ui ) => autoEffect ( ui , state , `a-${ name } ` , ( ) => ui . target . getAttribute ( name ) , ( value ) => ( element ) => ( ) => element . setAttribute ( name , value ) , ( element ) => ( ) => element . removeAttribute ( name ) ) ;
469
469
/**
470
470
* Toggle a boolan attribute of an element
471
471
*
472
472
* @since 0.8.0
473
473
* @param {string } name - name of attribute to be toggled
474
- * @param {StateLike } state - state bounded to the attribute existence
474
+ * @param {StateLike<boolean> } state - state bounded to the attribute existence
475
475
*/
476
- const toggleAttribute = ( name , state = name ) => ( ui ) => {
477
- const setter = ( value ) => ( element ) => ( ) => element . toggleAttribute ( name , value ) ;
478
- return autoEffect ( ui , state , `a-${ name } ` , ui . target . hasAttribute ( name ) , setter ( false ) , setter ) ;
479
- } ;
476
+ const toggleAttribute = ( name , state = name ) => ( ui ) => autoEffect ( ui , state , `a-${ name } ` , ( ) => ui . target . hasAttribute ( name ) , ( value ) => ( element ) => ( ) => element . toggleAttribute ( name , value ) ) ;
480
477
/**
481
478
* Toggle a classList token of an element
482
479
*
483
480
* @since 0.8.0
484
481
* @param {string } token - class token to be toggled
485
- * @param {StateLike } state - state bounded to the class existence
482
+ * @param {StateLike<boolean> } state - state bounded to the class existence
486
483
*/
487
- const toggleClass = ( token , state = token ) => ( ui ) => autoEffect ( ui , state , `c-${ token } ` , ui . target . classList . contains ( token ) , ( element ) => ( ) => element . classList . remove ( token ) , ( value ) => ( element ) => ( ) => element . classList . toggle ( token , value ) ) ;
484
+ const toggleClass = ( token , state = token ) => ( ui ) => autoEffect ( ui , state , `c-${ token } ` , ( ) => ui . target . classList . contains ( token ) , ( value ) => ( element ) => ( ) => element . classList . toggle ( token , value ) ) ;
488
485
/**
489
486
* Set a style property of an element
490
487
*
491
488
* @since 0.8.0
492
489
* @param {string } prop - name of style property to be set
493
- * @param {StateLike } state - state bounded to the style property value
490
+ * @param {StateLike<string> } state - state bounded to the style property value
494
491
*/
495
- const setStyle = ( prop , state = prop ) => ( ui ) => autoEffect ( ui , state , `s-${ prop } ` , ui . target . style [ prop ] , ( element ) => ( ) => element . style . removeProperty ( prop ) , ( value ) => ( element ) => ( ) => element . style [ prop ] = value ) ;
492
+ const setStyle = ( prop , state = prop ) => ( ui ) => autoEffect ( ui , state , `s-${ prop } ` , ( ) => ui . target . style . getPropertyValue ( prop ) , ( value ) => ( element ) => ( ) => element . style . setProperty ( prop , value ) , ( element ) => ( ) => element . style . removeProperty ( prop ) ) ;
496
493
497
494
/* === Exported Class and Functions === */
498
495
/**
0 commit comments