Skip to content

fix(AppShell): expression-editor parity for if/set/foreach templates - #2151

Merged
alexwarren merged 4 commits into
mainfrom
claude/trusting-lovelace-a81bd2
Aug 27, 2026
Merged

fix(AppShell): expression-editor parity for if/set/foreach templates#2151
alexwarren merged 4 commits into
mainfrom
claude/trusting-lovelace-a81bd2

Conversation

@alexwarren

@alexwarren alexwarren commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • The expression-template control renderer (ScriptEditor.svelte's expressionField snippet, used for if/set/foreach template controls) only offered a simple/expression toggle for objects and number/numberdouble controls.
    • RandomChance's percentile control (Engine/Core/CoreEditorExpressions.aslx, <minimum>0</minimum><maximum>100</maximum>) now renders a proper <input type="number" min max step>, and the equivalent GamebookCoreEditorExpressions.aslx control does too.
    • Every other simple-editor kind — the implicit textbox default (GetBoolean's "flag name", GetInt's "counter name", Ask's "question", etc.) and boolean (ShowMenu's "allow cancel") — now also gets the toggle, matching the property-panel/script-param pipelines.
    • A control with no <simple> tag at all (HasAttribute's "object", #object#.#property# = #value#'s "value") now renders the full wand-equipped ExpressionInput, matching v5, instead of a bare unstyled textbox.
  • WasmEditorBridge.cs no longer drops "label" controls (e.g. RandomChance's "% of the time", HasAttribute's "Object"/"Attribute" captions) from the attribute-only filter, and threads ControlType/Caption through ExpressionTemplateControlData so the frontend can render them in sequence with the value controls.
  • Fixed a bug where switching a control's toggle back to "simple" only cleared the override flag without resetting a non-simple-shaped value, so the simple widget never actually reappeared until the expression was manually cleared.
  • Fixed control widths: the condition/template picker and object-picker <select>s now size to their actual selected content instead of a fixed max-width, which either truncated long values or (since an unconstrained native <select> sizes to its widest option) stayed wide once a short one was picked. Landed on measuring the browser's own natural single-option layout via an offscreen probe <select> rather than any fixed/estimated reserve, since a native select's dropdown-arrow footprint is drawn by the OS/browser itself and no constant can promise to match it across environments.
  • ExpressionInput.svelte gained optional minCh/maxCh props so a field can size itself to its own live-typed content (grows as you type, not just after blur/Enter) instead of a fixed class; insertAtCursor now splices into that live text instead of the last-committed value, so opening the insert-object/function picker mid-typing no longer discards unsaved keystrokes.

Test plan

  • dotnet build --configuration Release (full solution) — succeeds
  • dotnet test --configuration Release — all tests pass
  • npm run check (svelte-check) in src/AppShell — 0 errors/warnings
  • npm run lint (eslint) in src/AppShell — clean
  • Manual verification in a local draft, per condition/template:
    • RandomChance, Got/not Got, GetBoolean/not GetBoolean, GetInt, HasAttribute all round-trip correctly between the visual editor and code view (e.g. RandomChance(GetRandomInt(1, 50)), GetBoolean(player, "opened"), HasAttribute(player, "described"))
    • Toggling a control to "expression" and back to "simple" resets a non-simple value instead of getting stuck
    • Condition/object <select>s render their full selected text at any length, confirmed via a diff check between the live control and an offscreen probe (actualWidth - naturalWidth === 0 in every case)
    • Typing a long expression grows the field live, mid-keystroke
  • node tests/e2e/find-affected-tests.mjs run; all flagged scripts pass except four pre-existing flakes (verify-appshell-multi-control-editors, verify-appshell-script-adder-filter, verify-appshell-tree-filter, verify-default-tree-state, verify-rename-invalid-name) individually confirmed via git stash to fail identically on the unmodified base branch — unrelated to this change

🤖 Generated with Claude Code

alexwarren and others added 2 commits August 25, 2026 10:48
… controls

The expression-template picker (e.g. RandomChance's percentile control)
had no number-input branch, so <simpleeditor>number</simpleeditor>
controls with <minimum>/<maximum> hints silently rendered as unbounded
text boxes instead of a bounded number input, unlike the property panel
and script editor pipelines.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…te controls

The expression-template control renderer (ScriptEditor.svelte's expressionField
snippet) only offered a simple/expression toggle for "objects" and
"number"/"numberdouble" controls. Every other simple editor kind - the
implicit "textbox" default used by GetBoolean's "flag name", GetInt's "counter
name", Ask's "question", etc., and "boolean" (ShowMenu's "allow cancel") - had
no escape hatch to an arbitrary expression at all. A control with no <simple>
tag whatsoever (HasAttribute's "object", #object#.#property# = #value#'s
"value") rendered as a bare unstyled textbox instead of the wand-equipped
ExpressionInput v5 showed for it.

- WasmEditorBridge.cs: stop dropping "label" controls (e.g. RandomChance's
  "% of the time", HasAttribute's "Object"/"Attribute" captions) from the
  attribute-only filter, and thread ControlType/Caption through
  ExpressionTemplateControlData so the frontend can render them.
- ScriptEditor.svelte: generalize the per-control toggle to every simpleEditor
  kind (reusing the existing toSimpleDisplay/fromSimpleToExpression/
  isSimpleValue helpers, loosened to a minimal structural type so both
  ScriptControlData and ExpressionTemplateControlData satisfy them), add the
  boolean yes/no/expression variant, and fall back to a full ExpressionInput
  for controls with no simple mode at all.
- Fix the toggle-back-to-simple bug where switching off "expression" only
  cleared the override flag without resetting a non-simple-shaped value, so
  the simple widget never actually reappeared until the expression was
  manually cleared.
- Size the condition/template picker and object-picker <select>s to their
  actual selected content instead of a fixed max-width (which either
  truncated long values or, since an unconstrained native <select> sizes to
  its widest *option*, stayed wide once a short one was picked). Text-measure
  approximations (ch-per-character, then a canvas measurement plus a guessed
  arrow-chrome reserve) still clipped by a character or so in practice, since
  a native select's arrow footprint is drawn by the OS/browser itself - fixed
  by asking the browser directly via an offscreen single-option probe
  <select>, which can't diverge from the real one's rendering.
- ExpressionInput.svelte: optional minCh/maxCh props so a field can size
  itself to its own live-typed content (measured via the same canvas
  technique, in lib/text-measure.ts) instead of a fixed class, growing as you
  type rather than only after a blur/Enter commit; insertAtCursor now splices
  into that live text instead of the last-committed value prop, so opening
  the insert-object/function picker mid-typing no longer discards unsaved
  keystrokes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alexwarren alexwarren changed the title fix(AppShell): wire up <minimum>/<maximum> for expression-template number controls fix(AppShell): expression-editor parity for if/set/foreach templates Aug 27, 2026
alexwarren and others added 2 commits August 27, 2026 16:26
main independently added an identical GetNumericHint(IEditorControl, string)
helper via #2148 while this branch had its own copy for the expression-
template code path, causing a CS0111 duplicate-member build failure once
merged. Drop this branch's copy and keep main's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 27, 2026

Copy link
Copy Markdown

Deploying quest with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1c85f2a
Status: ✅  Deploy successful!
Preview URL: https://fce6d1e6.quest-1qv.pages.dev
Branch Preview URL: https://claude-trusting-lovelace-a81.quest-1qv.pages.dev

View logs

@alexwarren
alexwarren merged commit 60f23dc into main Aug 27, 2026
17 checks passed
@alexwarren
alexwarren deleted the claude/trusting-lovelace-a81bd2 branch August 27, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant