Skip to content

Commit 6514435

Browse files
akoclaude
andcommitted
fix(pages): allow PopupWidth/PopupHeight = 0 (auto-size) (#713)
0 is Studio Pro's own default for a pop-up page's width/height (auto-size), verified live on 11.12: a PopupLayout page created by Studio Pro stores PopupWidth: 0 / PopupHeight: 0 and passes `mx check` with 0 errors. mxcli rejected 0 in two validators ("must be a positive number") and, even if allowed, both writers coerced <=0 -> 600 — so the user could never author an auto-size pop-up, and mxcli deviated from Studio Pro's default. - Validators reject only negative now: - mdl/visitor/visitor_page_v3.go (popupDimensionValue: n >= 0) - mdl/backend/pagemutator/mutator.go (coercePopupDimension: n < 0) - Builder defaults to 0/0 (was 600/600), matching Studio Pro - mdl/executor/cmd_pages_builder_v3.go - Both writers write the value verbatim; only a stray negative clamps to 0 - sdk/mpr/writer_pages.go, mdl/backend/modelsdk/page_write.go - DESCRIBE suppresses only the real default 0 (an explicit 600 round-trips) - mdl/executor/cmd_pages_describe.go No *int needed — 0 is a valid stored value, so unset and explicit-0 both store 0. Verified end-to-end: ran the bug-test through the modelsdk engine on a blank 11.12 project; BSON stores PopupWidth/Height 0 and `mx check` = 0 errors. Tests updated (visitor, executor builder, pagemutator) to assert 0 is accepted and the default is 0. Bug-test mdl-examples/bug-tests/713-popup-zero-dimensions.mdl. Symptom table row added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 57ab8f0 commit 6514435

11 files changed

Lines changed: 128 additions & 32 deletions

File tree

.claude/skills/fix-issue.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ to the symptom table below, so the next similar issue costs fewer reads.
5555
| CE0463 on a `datagrid` whose column uses `ColumnWidth: manual` + `Size: N` — Studio Pro resets the column `size` to `1` | The MDL `ColumnWidth:` keyword isn't mapped to the schema `width` enum, so `width` stays at its `autoFill` default; `size` only applies when `width=manual`, so the value is inconsistent. Regression from the Stream B keyword-path consolidation (the deleted `datagrid_builder.go` did `colPropString(col.Properties, "ColumnWidth", "autoFill")`) | `mdl/executor/widget_defs.go` `itemPropertyAliases` | Add the MDL→schema alias under `[datagrid]["columns"]`: `"width": {"ColumnWidth"}`. Bump `WidgetDefGeneratorVersion` so stale `.def.json` regenerate. General rule when a column/object-list property's MDL keyword differs from the `.mpk` schema key (not just case), add it to `itemPropertyAliases`; cross-check against the pre-B3 `datagrid_builder.go` `colProp*` calls for any other dropped mappings |
5656
| Nightly `mx check` reports `CE0117 "Error(s) in expression." at Log message activity 'Log message (warning)'` on Mendix 10.24.19+ but not 10.24.16 or 11.x | Mendix 10.24.19 tightened expression validation: `toString(<string>)` is now a type error (toString expects a non-string input). An example called `toString($OrderNumber)` where `$OrderNumber` was already a string parameter | The offending `log warning ... with ({1} = toString($stringVar))` — find via `~/.mxcli/mxbuild/{ver}/modeler/mx check`, then bisect with `drop microflow ...` until CE0117 disappears | Remove the redundant `toString()` wrapper around already-string values. Only wrap non-string values (integers, decimals, dates, enums) in `toString()`. The Mendix 11.x parser is more lenient and lets this slide, but 10.24.19+ rejects it |
5757
| A page-level property can't be set — `ALTER PAGE X { SET PopupWidth = 800; }` (or any page-level prop other than Title/Url) fails with `unsupported page-level property: …` | The page-level SET handler only special-cased a couple of properties; everything else fell through to the default error | `mdl/backend/pagemutator/mutator.go` → `applyPageLevelSetMut` (shared by both engines) | Add a `case` writing the field at the top level of the Forms$Page doc via `dSetOrAppend` with the on-disk BSON type (int64 for PopupWidth/PopupHeight, bool for PopupResizable — verify against a Studio Pro page with `mxcli bson dump --format bson`). Page-level prop names are **case-sensitive**. For DESCRIBE roundtrip, emit the values back in the CREATE PAGE header. CREATE-time support: add a generic `IDENTIFIER COLON propertyValueV3` to `pageHeaderPropertyV3` (regen grammar), recognize the keys in `parsePageHeaderV3` (`applyGenericPageHeaderProp`, error on unknown), carry `*int`/`*bool` on `CreatePageStmtV3`, default to 600/600/false in `buildPageV3`, and have both writers honour `page.Popup*` (legacy `sdk/mpr/writer_pages.go` int64; codec `mdl/backend/modelsdk/page_write.go` int32 via gen — tolerated by mx check). The MCP backend has its **own** `mcpPageMutator` (pg content tree, not raw BSON) — page-level SET there reaches `SetWidgetProperty("")`; map it or reject honestly (it rejects, pending a `pg_read_page` probe of the pop-up keys). Issue #661 |
58+
| `PopupWidth: 0` / `PopupHeight: 0` rejected ("must be a positive number") on CREATE or ALTER PAGE; user can't make an auto-size pop-up | 0 is actually Studio Pro's **default** for pop-up dimensions (auto-size) — verified live on 11.12: a pg-created PopupLayout page stores 0/0 and `mx check` = 0 errors. Two validators rejected ≤0, and both writers coerced ≤0→600, so even an allowed 0 became 600 | `mdl/visitor/visitor_page_v3.go` (`popupDimensionValue`) + `mdl/backend/pagemutator/mutator.go` (`coercePopupDimension`) + `mdl/executor/cmd_pages_builder_v3.go` (builder default) + `sdk/mpr/writer_pages.go` & `mdl/backend/modelsdk/page_write.go` (`popupDimension`) + `mdl/executor/cmd_pages_describe.go` | Relax both validators to reject only **negative**; default the builder to **0** (not 600, matching Studio Pro); drop the `≤0→600` coercion in both writers (clamp only negatives to 0); have DESCRIBE suppress only the real default 0 (emit an explicit 600). No `*int` needed — 0 is a valid stored value. Bug-test `mdl-examples/bug-tests/713-popup-zero-dimensions.mdl`. Issue #713 |
5859
| `Visible: [Attr != '']` / `Editable: […]` on a widget (CONTAINER, textbox, …) → CE0117 "Error(s) in expression." in Studio Pro on the legacy engine, and silently *ignored* on the modelsdk engine | Two bugs (NOT BSON structure): (1) the expression was emitted with a bare attribute reference (`Name != ''`) — a Mendix client expression must root attributes in the widget data context (`$currentObject/Name != ''`); (2) the modelsdk codec hardcoded `ConditionalVisibilitySettings` to null, dropping the expression entirely | `mdl/visitor/visitor_page_v3.go` → `buildConditionalExpression`/`conditionalExprToString`; `mdl/backend/modelsdk/widget_write.go` → `applyWidgetBase` + TypeDefaults | (1) For `VISIBLE`/`EDITABLE` xpath constraints, build the xpath AST and serialize via `conditionalExprToString`, which prefixes bare `IdentifierExpr` / non-variable-rooted `XPathPathExpr` with `$currentObject/` (leaves `$…`-rooted paths, literals, functions, enum qualified-names untouched). Do **not** apply this to datasource `where` clauses (those are real XPath). (2) In `applyWidgetBase`, type-assert `SetConditionalVisibilitySettings`/`SetConditionalEditabilitySettings` and emit a settings element when the model has one; register `Forms$ConditionalVisibilitySettings`/`…EditabilitySettings` TypeDefaults (`NullFields: Attribute,SourceVariable`; `MandatoryLists: Conditions[,ModuleRoles]`) so the null-when-unset slots stay null (the encoder only fills NullFields when not already emitted). **ALTER PAGE** had the same gap (`SET Visible = [expr]` parsed as a `propertyValueV3` array and silently no-op'd): add `VISIBLE/EDITABLE EQUALS xpathConstraint` alternatives to `alterPageAssignment` (regen grammar), route to `VisibleIf`/`EditableIf` in `buildAlterPageAssignment` (reusing `buildConditionalExpression`), and add `VisibleIf`/`EditableIf` cases to `setRawWidgetPropertyMut` (`mdl/backend/pagemutator/mutator.go`) that build the settings node via `setWidgetConditionalSettingMut` (rejecting editability on non-input widgets). The shared mutator covers both engines. Verify both engines with `mx check` = 0 errors. Issue #627 |
5960
| `visible: [$currentObject/Status = Mod.Enum.Value]` stored as `… = 'Value'` (string) → MxBuild CE0117 "Error(s) in expression" (v0.13.0 regression; both engines) | `conditionalExprToString` (added with #627) sent a qualified-enum `QualifiedNameExpr` to its `default` case → `xpathExprToString`, which converts a 3-part enum name to a string literal. Correct for an XPath *datasource* constraint (DB level), WRONG for a *client* visibility/editability expression (compares to the qualified enum value) | `mdl/visitor/visitor_page_v3.go``conditionalExprToString` | Add an explicit `*ast.QualifiedNameExpr` case returning `e.QualifiedName.String()` (the qualified literal) before the `default`. Leaves the datasource `where` path (`buildXPathString`/`xpathExprToString`) untouched, so DB-level enums still stringify to `'Value'`. Applies to CREATE and ALTER (both use `conditionalExprToString`). Verify the datasource enum still stores `'Value'` and the visibility enum stays qualified; `mx check` = 0 |
6061
| CE0488 "No entity configured for the data source of this data view" on a context (page-parameter-bound) data view authored over **MCP** — DESCRIBE looks correct (`dataview dvX (DataSource: $Param)`), but the model has no entity on the source. DataGrids with database sources are fine | `mapDataViewSource`'s `*pages.DataViewSource` case used a mutually-exclusive `switch`: when `ParameterName != ""` it wrote only `sourceVariable` and never `entityRef`. Studio Pro/pg write **both** entityRef AND sourceVariable for a context source (see `testdata/pg-page-contact-newedit.json`) | `mdl/backend/mcp/page_widgets.go``mapDataViewSource` | Drop the exclusive switch: set `entityRef` (DomainModels$DirectEntityRef) whenever `EntityName != ""` AND `sourceVariable` (Pages$PageVariable) whenever `ParameterName != ""`. The executor already resolves the parameter's entity into `EntityName` (`cmd_pages_builder_v3.go` parameter case), so both are available. MCP-only — the MPR engines were never affected |
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
-- ============================================================================
2+
-- Issue #713 — PopupWidth / PopupHeight = 0 must be allowed
3+
-- ============================================================================
4+
--
5+
-- Symptom: CREATE PAGE (… PopupWidth: 0, PopupHeight: 0) and
6+
-- ALTER PAGE … SET PopupWidth = 0 were rejected ("must be a positive number"),
7+
-- and even if allowed both writers coerced 0 -> 600.
8+
--
9+
-- Reality (verified against a live Studio Pro 11.12 model): 0 is Studio Pro's
10+
-- OWN default for a pop-up page's width/height — it means auto-size. A page
11+
-- created on Atlas_Core.PopupLayout stores PopupWidth: 0 / PopupHeight: 0 and
12+
-- passes `mx check` with 0 errors.
13+
--
14+
-- Fix: validators reject only negative values; the builder defaults to 0 (not
15+
-- 600); both writers write the value verbatim (no 0 -> 600 coercion); DESCRIBE
16+
-- suppresses only the real default 0.
17+
--
18+
-- To verify in Studio Pro:
19+
-- 1. Run this script.
20+
-- 2. Open Bug713.ThingPopupAuto — Pop-up width/height should be 0 (automatic).
21+
-- 3. Open Bug713.ThingPopupFixed — width 800, height 480.
22+
-- 4. `mx check` should report 0 errors.
23+
-- ============================================================================
24+
25+
CREATE MODULE Bug713;
26+
27+
CREATE PERSISTENT ENTITY Bug713.Thing (
28+
Name: String(200)
29+
);
30+
31+
-- Pop-up page with explicit 0/0 (auto-size) — the case the bug rejected.
32+
CREATE OR REPLACE PAGE Bug713.ThingPopupAuto (
33+
Title: 'Thing (auto-size pop-up)',
34+
Layout: Atlas_Core.PopupLayout,
35+
PopupWidth: 0,
36+
PopupHeight: 0,
37+
Params: { $Thing: Bug713.Thing }
38+
) {
39+
dataview dv (DataSource: $Thing) {
40+
textbox tb (Label: 'Name', Attribute: Name)
41+
}
42+
}
43+
44+
-- Pop-up page with explicit non-zero dimensions — must still round-trip.
45+
CREATE OR REPLACE PAGE Bug713.ThingPopupFixed (
46+
Title: 'Thing (fixed pop-up)',
47+
Layout: Atlas_Core.PopupLayout,
48+
PopupWidth: 800,
49+
PopupHeight: 480,
50+
Params: { $Thing: Bug713.Thing }
51+
) {
52+
dataview dv (DataSource: $Thing) {
53+
textbox tb (Label: 'Name', Attribute: Name)
54+
}
55+
}
56+
57+
-- ALTER must accept SET PopupWidth = 0 (auto-size) too.
58+
ALTER PAGE Bug713.ThingPopupFixed {
59+
SET PopupWidth = 0;
60+
SET PopupHeight = 0;
61+
}

mdl/backend/modelsdk/page_write.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ func (b *Backend) DeletePage(id model.ID) error {
8585
return b.writer.DeleteUnit(string(id))
8686
}
8787

88-
// popupDimension returns the pop-up width/height for the gen Page (int32),
89-
// falling back to the Mendix default (600) for an unset/non-positive value so
90-
// pages built without explicit pop-up dimensions keep valid defaults.
88+
// popupDimension returns the pop-up width/height for the gen Page (int32).
89+
// Studio Pro's own default is 0 (auto-size), so 0 is a valid value and is
90+
// written through verbatim (issue #713); only a stray negative is clamped to 0.
9191
func popupDimension(n int) int32 {
92-
if n <= 0 {
93-
return 600
92+
if n < 0 {
93+
return 0
9494
}
9595
return int32(n)
9696
}

mdl/backend/pagemutator/mutator.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,8 +1608,9 @@ func dSetOrAppend(doc bson.D, key string, value any) bson.D {
16081608
// coercePopupDimension converts an MDL numeric value to the int64 BSON form used
16091609
// by the page's PopupWidth/PopupHeight fields. Integer literals arrive from the
16101610
// visitor as int (strconv.Atoi); a value written with a decimal point arrives as
1611-
// float64. The result is bounds-checked to a positive int32-range pixel count —
1612-
// the range Studio Pro accepts — so silent overflow can't reach the serializer.
1611+
// float64. The result is bounds-checked to a non-negative int32-range pixel count
1612+
// — the range Studio Pro accepts — so silent overflow can't reach the serializer.
1613+
// 0 is valid: it is Studio Pro's default and means auto-size (issue #713).
16131614
func coercePopupDimension(prop string, value any) (int64, error) {
16141615
var n int64
16151616
switch v := value.(type) {
@@ -1630,8 +1631,8 @@ func coercePopupDimension(prop string, value any) (int64, error) {
16301631
default:
16311632
return 0, fmt.Errorf("%s value must be a number, got %T", prop, value)
16321633
}
1633-
if n <= 0 {
1634-
return 0, fmt.Errorf("%s must be a positive number, got %d", prop, n)
1634+
if n < 0 {
1635+
return 0, fmt.Errorf("%s must be >= 0 (0 = auto-size), got %d", prop, n)
16351636
}
16361637
if n > math.MaxInt32 {
16371638
return 0, fmt.Errorf("%s value %d is out of range", prop, n)

mdl/backend/pagemutator/mutator_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,13 +1033,26 @@ func TestSetPageLevel_PopupResizable(t *testing.T) {
10331033
}
10341034
}
10351035

1036+
// SET PopupWidth = 0 is valid — 0 is Studio Pro's default (auto-size) and must be
1037+
// stored verbatim, not rejected (issue #713).
1038+
func TestSetPageLevel_PopupWidth_Zero(t *testing.T) {
1039+
rawData := makeRawPage()
1040+
m := &Mutator{rawData: rawData, widgetFinder: findBsonWidget}
1041+
if err := m.SetWidgetProperty("", "PopupWidth", 0); err != nil {
1042+
t.Fatalf("SET PopupWidth = 0 should be accepted, got: %v", err)
1043+
}
1044+
if got := bsonnav.DGet(m.rawData, "PopupWidth"); got != int64(0) {
1045+
t.Errorf("PopupWidth = %v (%T), want int64(0)", got, got)
1046+
}
1047+
}
1048+
10361049
func TestSetPageLevel_Popup_Invalid(t *testing.T) {
10371050
cases := []struct {
10381051
name string
10391052
prop string
10401053
value any
10411054
}{
1042-
{"zero width", "PopupWidth", 0},
1055+
{"negative width", "PopupWidth", -1},
10431056
{"negative height", "PopupHeight", -10},
10441057
{"non-whole float", "PopupWidth", 12.5},
10451058
{"non-number width", "PopupWidth", "wide"},

mdl/executor/cmd_pages_builder_v3.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@ func (pb *pageBuilder) buildPageV3(s *ast.CreatePageStmtV3) (*pages.Page, error)
4343
URL: s.URL,
4444
MarkAsUsed: false,
4545
Excluded: s.Excluded,
46-
// Pop-up dimensions (issue #661): Mendix defaults, overridable in the
47-
// page header. The writers serialize these top-level Forms$Page fields.
48-
PopupWidth: 600,
49-
PopupHeight: 600,
46+
// Pop-up dimensions (issues #661, #713): Studio Pro's own default for a
47+
// pop-up page is 0/0 (auto-size) — verified against a live 11.12 model —
48+
// so an unset dimension stays 0, matching what Studio Pro stores. The
49+
// page header can override. The writers serialize these top-level
50+
// Forms$Page fields.
51+
PopupWidth: 0,
52+
PopupHeight: 0,
5053
PopupResizable: false,
5154
}
5255
if s.PopupWidth != nil {

mdl/executor/cmd_pages_describe.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ func describePage(ctx *ExecContext, name ast.QualifiedName) error {
106106
if folderPath := h.BuildFolderPath(foundPage.ContainerID); folderPath != "" {
107107
props = append(props, fmt.Sprintf("Folder: %s", mdlQuote(folderPath)))
108108
}
109-
// Pop-up dimensions (issue #661) — emit only non-default values so the
110-
// CREATE PAGE header round-trips. Defaults are 600/600/false; a non-pop-up
111-
// content page stores 0, which we also skip.
109+
// Pop-up dimensions (issues #661, #713) — emit only non-default values so
110+
// the CREATE PAGE header round-trips. Studio Pro's default is 0/0 (auto-size);
111+
// an explicit non-zero value (e.g. 600) is emitted so it round-trips.
112112
if rawData != nil {
113-
if w := toInt(rawData["PopupWidth"]); w != 0 && w != 600 {
113+
if w := toInt(rawData["PopupWidth"]); w != 0 {
114114
props = append(props, fmt.Sprintf("PopupWidth: %d", w))
115115
}
116-
if hgt := toInt(rawData["PopupHeight"]); hgt != 0 && hgt != 600 {
116+
if hgt := toInt(rawData["PopupHeight"]); hgt != 0 {
117117
props = append(props, fmt.Sprintf("PopupHeight: %d", hgt))
118118
}
119119
if r, ok := rawData["PopupResizable"].(bool); ok && r {

mdl/executor/cmd_pages_popup_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,16 @@ func TestBuildPageV3_PopupDimensions(t *testing.T) {
3838
}
3939
}
4040

41-
// When the header omits pop-up properties the Mendix defaults apply.
41+
// When the header omits pop-up properties the Studio Pro default applies: 0/0
42+
// (auto-size), matching what Studio Pro itself stores (issue #713).
4243
func TestBuildPageV3_PopupDefaults(t *testing.T) {
4344
s := &ast.CreatePageStmtV3{Name: ast.QualifiedName{Module: "M", Name: "P"}}
4445
page, err := newPopupPageBuilder().buildPageV3(s)
4546
if err != nil {
4647
t.Fatalf("buildPageV3: %v", err)
4748
}
48-
if page.PopupWidth != 600 || page.PopupHeight != 600 || page.PopupResizable {
49-
t.Errorf("got %d/%d/%v, want 600/600/false", page.PopupWidth, page.PopupHeight, page.PopupResizable)
49+
if page.PopupWidth != 0 || page.PopupHeight != 0 || page.PopupResizable {
50+
t.Errorf("got %d/%d/%v, want 0/0/false", page.PopupWidth, page.PopupHeight, page.PopupResizable)
5051
}
5152
}
5253

mdl/visitor/visitor_page_popup_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ func TestCreatePage_PopupHeaderProperties(t *testing.T) {
4040
}
4141
}
4242

43+
// PopupWidth: 0 is valid — 0 is Studio Pro's default (auto-size), so it must parse
44+
// and carry through as an explicit 0, not be rejected (issue #713).
45+
func TestCreatePage_PopupWidthZero(t *testing.T) {
46+
prog, errs := Build(`CREATE PAGE M.P (PopupWidth: 0, PopupHeight: 0) { CONTAINER c { DYNAMICTEXT t (Content: 'x') } };`)
47+
if len(errs) > 0 {
48+
t.Fatalf("PopupWidth/Height: 0 should parse cleanly, got: %v", errs)
49+
}
50+
stmt := prog.Statements[0].(*ast.CreatePageStmtV3)
51+
if stmt.PopupWidth == nil || *stmt.PopupWidth != 0 {
52+
t.Errorf("PopupWidth = %v, want explicit 0", stmt.PopupWidth)
53+
}
54+
if stmt.PopupHeight == nil || *stmt.PopupHeight != 0 {
55+
t.Errorf("PopupHeight = %v, want explicit 0", stmt.PopupHeight)
56+
}
57+
}
58+
4359
// Absent pop-up properties stay nil so the executor applies the Mendix defaults.
4460
func TestCreatePage_PopupHeaderOmitted(t *testing.T) {
4561
prog, errs := Build(`CREATE PAGE M.P (Title: 'x') { CONTAINER c { DYNAMICTEXT t (Content: 'x') } };`)
@@ -58,7 +74,6 @@ func TestCreatePage_PopupHeaderErrors(t *testing.T) {
5874
name, input, wantSubstr string
5975
}{
6076
{"unknown property", `CREATE PAGE M.P (Bogus: 5) { CONTAINER c { DYNAMICTEXT t (Content: 'x') } };`, "unknown page property"},
61-
{"zero width", `CREATE PAGE M.P (PopupWidth: 0) { CONTAINER c { DYNAMICTEXT t (Content: 'x') } };`, "PopupWidth must be a positive"},
6277
{"non-bool resizable", `CREATE PAGE M.P (PopupResizable: 5) { CONTAINER c { DYNAMICTEXT t (Content: 'x') } };`, "PopupResizable must be true or false"},
6378
}
6479
for _, c := range cases {

mdl/visitor/visitor_page_v3.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func (b *Builder) applyGenericPageHeaderProp(stmt *ast.CreatePageStmtV3, name st
135135
case "PopupWidth", "PopupHeight":
136136
n, ok := popupDimensionValue(val)
137137
if !ok {
138-
b.addError(fmt.Errorf("line %d:%d: %s must be a positive whole number of pixels, got %v",
138+
b.addError(fmt.Errorf("line %d:%d: %s must be a whole number of pixels >= 0 (0 = auto-size), got %v",
139139
tok.GetLine(), tok.GetColumn(), name, val))
140140
return
141141
}
@@ -159,16 +159,17 @@ func (b *Builder) applyGenericPageHeaderProp(stmt *ast.CreatePageStmtV3, name st
159159
}
160160
}
161161

162-
// popupDimensionValue accepts a positive whole number within int32 range from the
163-
// generic property value (int literal → int, decimal literal → float64).
162+
// popupDimensionValue accepts a non-negative whole number within int32 range from
163+
// the generic property value (int literal → int, decimal literal → float64). 0 is
164+
// valid — it is Studio Pro's default and means auto-size (issue #713).
164165
func popupDimensionValue(v any) (int, bool) {
165166
switch n := v.(type) {
166167
case int:
167-
if n > 0 && n <= math.MaxInt32 {
168+
if n >= 0 && n <= math.MaxInt32 {
168169
return n, true
169170
}
170171
case float64:
171-
if n == math.Trunc(n) && n > 0 && n <= math.MaxInt32 {
172+
if n == math.Trunc(n) && n >= 0 && n <= math.MaxInt32 {
172173
return int(n), true
173174
}
174175
}

0 commit comments

Comments
 (0)