Skip to content

Commit

Permalink
fix: map falsy boolean properties as undefined
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivirkki committed Dec 13, 2023
1 parent 04ece1e commit 2c4a4c4
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 3 deletions.
18 changes: 16 additions & 2 deletions src/utils/createComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
type WebComponentProps as _WebComponentProps,
} from '@lit-labs/react';
import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
import type React from 'react';
import React from 'react';
import type { RefAttributes } from 'react';
import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';

Expand Down Expand Up @@ -81,7 +81,7 @@ export function createComponent<I extends HTMLElement, E extends EventNames = {}
export function createComponent<I extends HTMLElement, E extends EventNames = {}>(options: Options<I, E>): any {
const { elementClass } = options;

return _createComponent(
const component = _createComponent(
'_properties' in elementClass
? {
...options,
Expand All @@ -98,4 +98,18 @@ export function createComponent<I extends HTMLElement, E extends EventNames = {}
}
: options,
);

return React.forwardRef<typeof component, Parameters<typeof component>[0]>((props, ref) => {
// Map falsy boolean properties as `undefined` to avoid them from rendering with the
// value "false" in the attribute, for example `<vaadin-button hidden="false">`,
// which would actually evaluate as `hidden` being `true`.
const falsyBooleanProps = Object.entries(props).reduce((acc, [key, value]) => {
if (value === false) {
return { ...acc, [key]: undefined };
}
return acc;
}, {});

return React.createElement(component, { ...props, ...falsyBooleanProps, ref });
});
}
27 changes: 26 additions & 1 deletion test/Select.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import chaiDom from 'chai-dom';
import type { ReactElement } from 'react';
import { ListBox } from '../src/ListBox.js';
import { Item } from '../src/Item.js';
import { Select } from '../src/Select.js';
import { Select, SelectElement } from '../src/Select.js';
import { findByQuerySelector } from './utils/findByQuerySelector.js';

useChaiPlugin(chaiDom);
Expand Down Expand Up @@ -143,4 +143,29 @@ describe('Select', () => {
await expect(findByQuerySelector('div[slot="prefix"]')).to.eventually.have.text('Value:');
});
});

describe('boolean property', () => {
const booleanProperties: Array<keyof typeof SelectElement.prototype & string> = [
'disabled',
'hidden',
'opened',
'draggable',
];

booleanProperties.forEach((property) => {
describe(property, () => {
it(`should be true in the element if ${property} prop is true`, async () => {
render(<Select items={[{ label: 'foo', value: 'foo' }]} {...{ [property]: true }} />);
const select = await findByQuerySelector('vaadin-select');
expect(select[property]).to.be.ok;
});

it(`should be false in the element if ${property} prop is false`, async () => {
render(<Select items={[{ label: 'foo', value: 'foo' }]} {...{ [property]: false }} />);
const select = await findByQuerySelector('vaadin-select');
expect(select[property]).not.to.be.ok;
});
});
});
});
});
33 changes: 33 additions & 0 deletions test/SideNav.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { expect, use as useChaiPlugin } from '@esm-bundle/chai';
import { render } from '@testing-library/react';
import chaiDom from 'chai-dom';
import { SideNav, SideNavElement } from '../src/SideNav.js';
import { findByQuerySelector } from './utils/findByQuerySelector.js';

useChaiPlugin(chaiDom);

describe('SideNav', () => {
describe('boolean property', () => {
const booleanProperties: Array<keyof typeof SideNavElement.prototype & string> = [
'hidden',
'collapsed',
'draggable',
];

booleanProperties.forEach((property) => {
describe(property, () => {
it(`should be true in the element if ${property} prop is true`, async () => {
render(<SideNav {...{ [property]: true }} />);
const sideNav = await findByQuerySelector('vaadin-side-nav');
expect(sideNav[property]).to.be.ok;
});

it(`should be false in the element if ${property} prop is false`, async () => {
render(<SideNav {...{ [property]: false }} />);
const sideNav = await findByQuerySelector('vaadin-side-nav');
expect(sideNav[property]).not.to.be.ok;
});
});
});
});
});

0 comments on commit 2c4a4c4

Please sign in to comment.