Show boolean properties that default to true as checked (#2298)

Fixes #747

Boolean properties that default to `true` (`fill-antialias`,
`text-keep-upright`, `fill-extrusion-vertical-gradient`) showed an empty
checkbox when unset, so the first click wrote `true` and nothing changed
on the map. `InputCheckbox` now falls back to the spec default that
`InputSpec` already passes (as `InputEnum` does), and a click toggles
from what is shown. The Cluster checkbox in the sources modal passes no
default, so it behaves as before.

## Launch Checklist

 - [x] Briefly describe the changes in this PR.
 - [x] Link to related issues.
- [x] Include before/after visuals or gifs if this PR includes visual
changes.
 - [x] Write tests for all new functionality.
 - [x] Add an entry to `CHANGELOG.md` under the `## main` section.

Added two e2e tests on `fill-antialias` (checked when unset, one click
writes `false`).

## Screenshots

"Extrusion vertical gradient" on a `fill-extrusion` layer with the
property unset, before and after:

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/a2f4f4d2-9b1e-4b1b-89db-2a6a1f0b922a)
|
![after](https://github.com/user-attachments/assets/64e79b7b-1a9c-40e6-8040-9ac082ef998c)
|
| ![before,
zoomed](https://github.com/user-attachments/assets/482cb984-4927-4e32-81cb-2fce75c3a25d)
| ![after,
zoomed](https://github.com/user-attachments/assets/5d135d3d-910a-49ff-9837-b931132e7a30)
|

## Video

The video shows the same row on a small extrusion style, and one click
turning the gradient off.


https://github.com/user-attachments/assets/8ebc2f5a-923b-4022-82da-07cbd1eda783

Fix written with Claude Code; video is an automated browser run of this
branch recorded by User Stories Bot.
This commit is contained in:
shkomg
2026-11-03 17:22:41 +02:00
committed by GitHub
parent 9ccf742131
commit 2ff1a62d19
4 changed files with 21 additions and 6 deletions
+1
View File
@@ -19,6 +19,7 @@
- Keyboard shortcuts now keep working while the map has focus, instead of going dead until the map is blurred - Keyboard shortcuts now keep working while the map has focus, instead of going dead until the map is blurred
- The map no longer stays blank on load until it is moved, when the style loads before the map is ready - The map no longer stays blank on load until it is moved, when the style loads before the map is ready
- The debug modal now shows the MapLibre options for any renderer other than OpenLayers (e.g. `mbgljs`) - The debug modal now shows the MapLibre options for any renderer other than OpenLayers (e.g. `mbgljs`)
- Checkboxes for properties that default to `true` (e.g. `fill-antialias`, `text-keep-upright`) are now shown checked when the property is unset
- _...Add new stuff here..._ - _...Add new stuff here..._
## 3.1.0 ## 3.1.0
+11
View File
@@ -540,6 +540,17 @@ describe("layer editor", () => {
layers: [{ id, type: "fill", source: "example", paint: { "fill-opacity": 0.4 } }], layers: [{ id, type: "fill", source: "example", paint: { "fill-opacity": 0.4 } }],
}); });
}); });
test("antialias is checked when unset, as it defaults to true", async () => {
await then(get.element("[data-wd-key='spec-field:fill-antialias'] input")).shouldBeChecked();
});
test("unchecking antialias sets it to false", async () => {
await when.clickWithin("spec-field:fill-antialias", "input");
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id, type: "fill", source: "example", paint: { "fill-antialias": false } }],
});
});
}); });
describe("json-editor", () => { describe("json-editor", () => {
+1
View File
@@ -108,6 +108,7 @@ export class Assertable<T> {
shouldBeFocused = () => expect(this.locator().first()).toBeFocused(); shouldBeFocused = () => expect(this.locator().first()).toBeFocused();
shouldNotBeFocused = () => expect(this.locator().first()).not.toBeFocused(); shouldNotBeFocused = () => expect(this.locator().first()).not.toBeFocused();
shouldHaveValue = (value: string) => expect(this.locator().first()).toHaveValue(value); shouldHaveValue = (value: string) => expect(this.locator().first()).toHaveValue(value);
shouldBeChecked = () => expect(this.locator().first()).toBeChecked();
shouldContainText = async (text: string) => { shouldContainText = async (text: string) => {
const locator = this.locator(); const locator = this.locator();
// Prefer the visible element when a testid resolves to several (only the // Prefer the visible element when a testid resolves to several (only the
+8 -6
View File
@@ -2,20 +2,22 @@ import React from "react";
export type InputCheckboxProps = { export type InputCheckboxProps = {
value?: boolean value?: boolean
default?: boolean
style?: object style?: object
onChange(...args: unknown[]): unknown onChange(...args: unknown[]): unknown
}; };
export class InputCheckbox extends React.Component<InputCheckboxProps> { export class InputCheckbox extends React.Component<InputCheckboxProps> {
static defaultProps = { isChecked() {
value: false, return this.props.value ?? this.props.default ?? false;
}; }
onChange = () => { onChange = () => {
this.props.onChange(!this.props.value); this.props.onChange(!this.isChecked());
}; };
render() { render() {
const checked = this.isChecked();
return <div className="maputnik-checkbox-wrapper"> return <div className="maputnik-checkbox-wrapper">
<input <input
className="maputnik-checkbox" className="maputnik-checkbox"
@@ -23,11 +25,11 @@ export class InputCheckbox extends React.Component<InputCheckboxProps> {
style={this.props.style} style={this.props.style}
onChange={this.onChange} onChange={this.onChange}
onClick={this.onChange} onClick={this.onChange}
checked={this.props.value} checked={checked}
/> />
<div className="maputnik-checkbox-box"> <div className="maputnik-checkbox-box">
<svg style={{ <svg style={{
display: this.props.value ? "inline" : "none" display: checked ? "inline" : "none"
}} className="maputnik-checkbox-icon" viewBox='0 0 32 32'> }} className="maputnik-checkbox-icon" viewBox='0 0 32 32'>
<path d='M1 14 L5 10 L13 18 L27 4 L31 8 L13 26 z' /> <path d='M1 14 L5 10 L13 18 L27 4 L31 8 L13 26 z' />
</svg> </svg>