diff --git a/packages/leaner/src/web/classes.js b/packages/leaner/src/web/classes.js
index e62976b..9eb99ed 100644
--- a/packages/leaner/src/web/classes.js
+++ b/packages/leaner/src/web/classes.js
@@ -7,15 +7,17 @@ export function setClasses( element, classes ) {
if ( Array.isArray( value ) ) {
element.className = '';
element.classList.add( ...value );
- } else {
+ } else if ( value != null ) {
element.className = value;
+ } else {
+ element.removeAttribute( 'class' );
}
} );
} else if ( isPlainObject( classes ) ) {
setClassesObject( element, classes );
} else if ( Array.isArray( classes ) ) {
setClassesArray( element, classes );
- } else {
+ } else if ( classes != null ) {
element.className = classes;
}
}
@@ -54,7 +56,7 @@ function setClassesArray( element, classes ) {
} );
} else if ( isPlainObject( item ) ) {
setClassesObject( element, item );
- } else {
+ } else if ( item != null ) {
element.classList.add( item );
}
}
diff --git a/packages/leaner/src/web/make.js b/packages/leaner/src/web/make.js
index f9148c7..ee21b60 100644
--- a/packages/leaner/src/web/make.js
+++ b/packages/leaner/src/web/make.js
@@ -97,9 +97,9 @@ function setElementProperty( element, key, value ) {
element.addEventListener( key.substring( 2 ), value );
} else if ( Properties.has( key ) ) {
if ( typeof value == 'function' )
- reactive( value, value => element[ key ] = value );
+ reactive( value, value => element[ key ] = value != null ? value : '' );
else
- element[ key ] = value;
+ element[ key ] = value != null ? value : '';
} else {
if ( typeof value == 'function' )
reactive( value, value => setElementAttribute( element, key, value ) );
diff --git a/packages/leaner/src/web/styles.js b/packages/leaner/src/web/styles.js
index 37f1dcc..ec7e107 100644
--- a/packages/leaner/src/web/styles.js
+++ b/packages/leaner/src/web/styles.js
@@ -8,13 +8,15 @@ export function setStyles( element, styles ) {
element.style = '';
for ( const [ key, value ] of Object.entries( value ) )
setStyleProperty( element, key, value );
- } else {
+ } else if ( value != null ) {
element.style = value;
+ } else {
+ element.removeAttribute( 'style' );
}
} );
} else if ( isPlainObject( styles ) ) {
setStylesObject( element, styles );
- } else {
+ } else if ( styles != null ) {
element.style = styles;
}
}
@@ -22,13 +24,15 @@ export function setStyles( element, styles ) {
function setStylesObject( element, styles ) {
for ( const [ key, value ] of Object.entries( styles ) ) {
if ( typeof value == 'function' )
- reactive( value, value => element.style[ key ] = value );
+ reactive( value, value => setStyleProperty( element, key, value ) );
else
setStyleProperty( element, key, value );
}
}
function setStyleProperty( element, key, value ) {
+ if ( value == null )
+ value = '';
if ( key.startsWith( '--' ) )
element.style.setProperty( key, value );
else
diff --git a/packages/leaner/test/web/classes.spec.js b/packages/leaner/test/web/classes.spec.js
index f460d4e..7068de6 100644
--- a/packages/leaner/test/web/classes.spec.js
+++ b/packages/leaner/test/web/classes.spec.js
@@ -10,12 +10,24 @@ describe( 'classes', () => {
expect( element.className ).toBe( 'btn-primary is-large' );
} );
+ test( 'undefined', () => {
+ const element = make( [ 'button', { type: 'button', class: undefined } ] );
+
+ expect( element.outerHTML ).toBe( '' );
+ } );
+
test( 'static array', () => {
const element = make( [ 'button', { type: 'button', class: [ 'btn-primary', 'is-large' ] } ] );
expect( element.className ).toBe( 'btn-primary is-large' );
} );
+ test( 'static array with undefined', () => {
+ const element = make( [ 'button', { type: 'button', class: [ 'btn-primary', 'is-large', undefined ] } ] );
+
+ expect( element.className ).toBe( 'btn-primary is-large' );
+ } );
+
test( 'dynamic value', () => {
const [ value, setValue ] = state( 'btn-primary' );
diff --git a/packages/leaner/test/web/make.spec.js b/packages/leaner/test/web/make.spec.js
index a410a05..7889233 100644
--- a/packages/leaner/test/web/make.spec.js
+++ b/packages/leaner/test/web/make.spec.js
@@ -47,6 +47,13 @@ describe( 'make()', () => {
expect( element.value ).toBe( 'hello' );
} );
+ test( 'undefined value', () => {
+ const element = make( [ 'input', { value: undefined } ] );
+
+ expect( element ).toBeInstanceOf( HTMLInputElement );
+ expect( element.value ).toBe( '' );
+ } );
+
test( 'dynamic content', () => {
const [ value, setValue ] = state( 'test' );
@@ -62,6 +69,13 @@ describe( 'make()', () => {
expect( element.textContent ).toBe( 'hello' );
} );
+ test( 'undefined content', () => {
+ const element = make( [ 'p', undefined ] );
+
+ expect( element ).toBeInstanceOf( HTMLElement );
+ expect( element.textContent ).toBe( '' );
+ } );
+
test( 'dynamic attribute', () => {
const [ value, setValue ] = state( 'test' );
@@ -77,6 +91,13 @@ describe( 'make()', () => {
expect( element.outerHTML ).toBe( '' );
} );
+ test( 'undefined attribute', () => {
+ const element = make( [ 'label', { for: undefined }, 'hello' ] );
+
+ expect( element ).toBeInstanceOf( HTMLLabelElement );
+ expect( element.outerHTML ).toBe( '' );
+ } );
+
test( 'remove attribute', () => {
const [ value, setValue ] = state( 'test' );
diff --git a/packages/leaner/test/web/styles.spec.js b/packages/leaner/test/web/styles.spec.js
index 0b1f677..672faa5 100644
--- a/packages/leaner/test/web/styles.spec.js
+++ b/packages/leaner/test/web/styles.spec.js
@@ -10,6 +10,12 @@ describe( 'styles', () => {
expect( element.style.display ).toBe( 'none' );
} );
+ test( 'undefined', () => {
+ const element = make( [ 'button', { type: 'button', style: undefined } ] );
+
+ expect( element.outerHTML ).toBe( '' );
+ } );
+
test( 'static object', () => {
const element = make( [ 'button', { type: 'button', style: { display: 'none' } } ] );
@@ -44,5 +50,19 @@ describe( 'styles', () => {
expect( element.style.display ).toBe( 'inline' );
} );
+ test( 'dynamic object with undefined', () => {
+ const [ value, setValue ] = state( 'none' );
+
+ const element = make( [ 'button', { type: 'button', style: { display: value } } ] );
+
+ expect( element.style.display ).toBe( 'none' );
+
+ setValue( undefined );
+
+ runSchedule();
+
+ expect( element.style.display ).toBe( '' );
+ } );
+
// NOTE: custom properties cannot be tested because of https://github.com/jsdom/jsdom/issues/1895
} );