material-web icon indicating copy to clipboard operation
material-web copied to clipboard

Add coercing to properties to ensure type safety (`disabled = undefined || null` is not supported)

Open jackwilsdon opened this issue 1 year ago • 5 comments

What is affected?

Component

Description

When I set disabled to undefined on an md-slider, the slider is disabled.

Reproduction

https://lit.dev/playground/#project=W3sibmFtZSI6Im15LWV4YW1wbGUudHMiLCJjb250ZW50IjoiaW1wb3J0IHtodG1sLCBjc3MsIExpdEVsZW1lbnR9IGZyb20gJ2xpdCc7XG5pbXBvcnQge2N1c3RvbUVsZW1lbnR9IGZyb20gJ2xpdC9kZWNvcmF0b3JzLmpzJztcbmltcG9ydCAnQG1hdGVyaWFsL3dlYi9zbGlkZXIvc2xpZGVyJztcblxuQGN1c3RvbUVsZW1lbnQoJ215LWV4YW1wbGUnKVxuZXhwb3J0IGNsYXNzIE15RXhhbXBsZSBleHRlbmRzIExpdEVsZW1lbnQge1xuICBzdGF0aWMgc3R5bGVzID0gY3NzYFxuICAgIGlucHV0IHtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIH1cbiAgYDtcbiAgXG4gIHJlbmRlcigpIHtcbiAgICByZXR1cm4gaHRtbGBcbiAgICAgIDxtZC1zbGlkZXIgLmRpc2FibGVkPSR7bnVsbH0-PC9tZC1zbGlkZXI-XG4gICAgICA8bWQtc2xpZGVyIC5kaXNhYmxlZD0ke3VuZGVmaW5lZH0-PC9tZC1zbGlkZXI-XG4gICAgICA8aW5wdXQgdHlwZT1cInRleHRcIiAuZGlzYWJsZWQ9JHtudWxsfSAvPlxuICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgLmRpc2FibGVkPSR7dW5kZWZpbmVkfSAvPlxuICAgIGA7XG4gIH1cbn1cbiJ9LHsibmFtZSI6ImluZGV4Lmh0bWwiLCJjb250ZW50IjoiPCFET0NUWVBFIGh0bWw-XG48aGVhZD5cbiAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCIgc3JjPVwiLi9teS1leGFtcGxlLmpzXCI-PC9zY3JpcHQ-XG48L2hlYWQ-XG48Ym9keT5cbiAgPG15LWV4YW1wbGU-PC9teS1leGFtcGxlPlxuPC9ib2R5PlxuIn0seyJuYW1lIjoicGFja2FnZS5qc29uIiwiY29udGVudCI6IntcbiAgXCJkZXBlbmRlbmNpZXNcIjoge1xuICAgIFwibGl0XCI6IFwiXjMuMC4wXCIsXG4gICAgXCJAbGl0L3JlYWN0aXZlLWVsZW1lbnRcIjogXCJeMi4wLjBcIixcbiAgICBcImxpdC1lbGVtZW50XCI6IFwiXjQuMC4wXCIsXG4gICAgXCJsaXQtaHRtbFwiOiBcIl4zLjAuMFwiXG4gIH1cbn0iLCJoaWRkZW4iOnRydWV9XQ

Workaround

Set disabled to null instead of undefined to disable a slider.

Is this a regression?

Yes. This used to work, but now it doesn't.

Affected versions

1.1.1

Browser/OS/Node environment

Browser: Firefox 121.0 OS: macOS 14.2

jackwilsdon avatar Dec 31 '23 15:12 jackwilsdon

It looks like this was introduced in 2234a1279fb945f038cc29bfe1bba073bffe2252 and possibly affects more than just sliders.

jackwilsdon avatar Dec 31 '23 15:12 jackwilsdon

I think it's a code issue? Your code renders this HTML so it's correctly disabled:

image

Removing the attribute correctly enables it: Lit Playground

datvm avatar Dec 31 '23 19:12 datvm

The issue is that rendering with .disabled=${undefined} (incorrectly) disables the field. The native HTML input element treats undefined the same as false when setting "disabled", as did @material/web up until 1.1.1. I don't think setting disabled to undefined should disable the field.

jackwilsdon avatar Dec 31 '23 19:12 jackwilsdon

Seems like the behaviour was actually changed in v1.1.0.

Here's a playground using 1.0.1

And one using 1.1.0

Note that the second slider is enabled in 1.0.1 but not 1.1.0.

jackwilsdon avatar Dec 31 '23 19:12 jackwilsdon

Overall this is related to coercing property values.

We do not coerce at runtime and expect type adherence, so setting slider.disabled = undefined may result in type issues where we expect an explicit boolean.

As a workaround, we recommend using typescript and lit-analyzer to ensure type safety, then ensuring default types where the types do not match. For example:

<md-slider .disabled=${this.disabledOrNull ?? false}>

Coercing would be a good feature to add though (updated the title).

slider.disabled = null;
console.log(slider.disabled); // `false` expected

This would help with edge cases where type safety is not guaranteed, such as removing attributes with Lit's default boolean attribute converter.

We can use our own attribute converters and/or decorators to provide some default coercing features that match platform expectations for coercing.

asyncliz avatar Jan 02 '24 19:01 asyncliz