You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(web-ui): Picker(onChange) receives its callback - #14692
On --target web, Picker(onChange) never calls onChange: choosing an option does nothing. perry/ui declares Picker(onChange: (index: number) => void), so codegen passes the closure as the first argument of perry_ui_picker_create in crates/perry-codegen-wasm/src/wasm_runtime.js, but that bridge takes (items_json, selected, callback), so the closure landed in items_json and callback stayed undefined. A closure in the first slot is now taken as onChange; the three-argument shape still works. The new __isPerryClosure recognises a {funcIdx} handle object or a host function.
Changes
crates/perry-codegen-wasm/src/wasm_runtime.js: perry_ui_picker_create accepts Picker(onChange); new __isPerryClosure.
crates/perry-codegen-wasm/src/emit/tests.rs: picker_on_change_is_called_with_the_chosen_index, plus the shared run_web_ui_source_then helper (below).
Related issue
n/a (found while porting a filter page to --target web).
Test plan
macOS 27.3 arm64, Node 26.12.1, nightly from rust-toolchain.toml. main below is fee15e5049.
cargo test -p perry-codegen-wasm
main
this branch
new test
FAIL: left: ""
PASS
mutation: this branch with only wasm_runtime.js reverted to main
new test FAILS again; restoring the file (same shasum) passes it
perry-codegen-wasm
76 passed
77 passed
Also run, main vs the five web-ui fixes merged together (each fix touches only its own runtime function):
Browser check: the program below compiled with perry compile f.ts --target web -o f.html, loaded in headless Chrome (--headless=new --dump-dom) with a small script appended that selects the second option, dispatches change and reads the log text:
I did not run the full workspace test command from the template.
Shared test helper
emit/tests.rs gains run_web_ui_source_then, which boots a compiled program against a small element tree (WIDGET_DOM: children, text, listeners fired by dispatch(type), descendant tag selectors for querySelector) instead of the flat stub, so a test can build a widget, send it an event and read the DOM it produced. The existing run_web_source_then keeps the flat stub. The same helper hunk is byte-identical in the sibling web-ui PRs (Toggle, Picker, Section, Image, Table), and each test sits at a different spot in the file, so the five merge in any order without conflicts; I checked this with an octopus merge of all five branches onto main (clean, 81 tests pass).
Checklist
I have NOT bumped the workspace version or edited CHANGELOG.md (maintainer handles these at merge)
My commits follow the loose feat: / fix: / docs: / chore: prefix convention used in the log
perry/ui declares `Picker(onChange)`, so codegen hands the closure to
`perry_ui_picker_create` as its first argument, which the web runtime named
`items_json`; the callback slot stayed undefined and choosing an option never
called back. A closure in the first slot is now taken as onChange; the
three-argument (items_json, selected, callback) shape still works.
`__isPerryClosure` recognises a `{funcIdx}` handle object or a host function.
emit/tests.rs gains run_web_ui_source_then (shared with the Toggle fix), which
boots a program against a small element tree so a test can send a widget an
event.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUQanVsnitcrmYLAWWPc3p
The web runtime now accepts Picker(onChange) when the callback is the only argument. A test selects the second option, dispatches a change event, and checks that the callback receives index 1.
The runtime identifies functions and Perry closure objects as callbacks. When the third argument is omitted, perry_ui_picker_create treats the first argument as the callback. The changelog describes the web callback behavior.
DOM test support and callback test crates/perry-codegen-wasm/src/emit/tests.rs
The test helpers support configurable DOM stubs and a fake element tree. The Picker UI test changes the selected option, dispatches change, and checks that the callback logs index 1.
Picker(onChange) under the web target now calls its callback with the chosen index. A small inconsistency remains in how raw host functions are accepted but then ignored; no current caller is known to trigger it. This is low risk to merge.
Pre-merge checks: 4
Check name
Status
Explanation
Title check
The title names the main change: Picker(onChange) now receives its callback in the web UI target. It uses the conventional fix(web-ui) prefix and matches the changelog entry, the wasm_runtime.js chang…
Description check
The description follows the template's main sections: Summary, Changes, Related issue, Test plan, and Checklist. The Summary explains the bug and the fix. Changes lists both touched files. The Related…
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Title check
Explanation
The title names the main change: Picker(onChange) now receives its callback in the web UI target. It uses the conventional fix(web-ui) prefix and matches the changelog entry, the wasm_runtime.js change, and the new test. It is 51 characters and 5 words, so it stays concise.
Full details: Description check
Explanation
The description follows the template's main sections: Summary, Changes, Related issue, Test plan, and Checklist. The Summary explains the bug and the fix. Changes lists both touched files. The Related issue is marked n/a with a reason. The Test plan gives concrete commands, results, and a browser check. The template's Screenshots section is optional and is omitted, which is acceptable. The checklist items are checked. The test plan does not tick the template's workspace-wide test command, and the author says that command was not run. The template asks that boxes pass before merge, so this gap is worth noting. The description does not mention the template's Cargo.toml version and CHANGELOG rules beyond the checklist, which the author did confirm. The description also includes a changelog-related commit in the objectives, which the description does not mention, but this does not affect the check.
Finishing Touches
Generate unit tests (beta)
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Overlap with #14664: both PRs add function __isPerryClosure to wasm_runtime.js. #14664's version checks the __perryClosures WeakSet that __newClosure fills; this PR's checks for a funcIdx field or a host function. The two merge without a textual conflict, but JS keeps only the later declaration (this PR's), and then #14664's a_closure_used_as_a_value_is_a_function fails (git merge of both heads, cargo test -p perry-codegen-wasm: 79 passed, 1 failed).
Resolution: the merged tree needs only #14664's definition. With this PR's 7-line __isPerryClosure block removed, the same merged tree passes 80 of 80, including picker_on_change_is_called_with_the_chosen_index, because the closure Picker receives is the object __newClosure registered. So whichever lands second should drop this PR's definition: if #14664 lands first, this PR should not add its own; if this PR lands first, #14664 should replace it.
2863-2863: Minor · Functional Correctness · Quick win
Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.
Handle direct host functions in callWasmClosure.
This predicate accepts a host function, and the new Picker branch stores that function as _perryCallback. However, callWasmClosure initializes closure only for object or number inputs. A direct function returns at Line 2877 without invocation.
Accept function inputs in that resolver, and add a host-function regression case. The new test covers only compiled closure objects.
Review info
Run configuration
Source mode: Auto
Repository: Unavailable
Branch: Unavailable
File: No configuration file from this repository applied
Commit: Unavailable
Layers: defaults
Review profile: CHILL
Plan: Advanced
Run ID: a58466fb-2994-45f0-8431-ee57a91e029c
Commits
Reviewing files that changed from the base of the PR and between fee15e5 and bb31449.
Files selected for processing: 3
changelog.d/14692-web-ui-picker-callback.md
crates/perry-codegen-wasm/src/emit/tests.rs
crates/perry-codegen-wasm/src/wasm_runtime.js
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On
--target web,Picker(onChange)never callsonChange: choosing an option does nothing. perry/ui declaresPicker(onChange: (index: number) => void), so codegen passes the closure as the first argument ofperry_ui_picker_createincrates/perry-codegen-wasm/src/wasm_runtime.js, but that bridge takes(items_json, selected, callback), so the closure landed initems_jsonandcallbackstayedundefined. A closure in the first slot is now taken asonChange; the three-argument shape still works. The new__isPerryClosurerecognises a{funcIdx}handle object or a host function.Changes
crates/perry-codegen-wasm/src/wasm_runtime.js:perry_ui_picker_createacceptsPicker(onChange); new__isPerryClosure.crates/perry-codegen-wasm/src/emit/tests.rs:picker_on_change_is_called_with_the_chosen_index, plus the sharedrun_web_ui_source_thenhelper (below).Related issue
n/a (found while porting a filter page to
--target web).Test plan
macOS 27.3 arm64, Node 26.12.1, nightly from
rust-toolchain.toml.mainbelow isfee15e5049.mainleft: ""wasm_runtime.jsreverted tomainperry-codegen-wasmAlso run,
mainvs the five web-ui fixes merged together (each fix touches only its own runtime function):mainrustfmt --check --edition 2021 crates/perry-codegen-wasm/src/emit/tests.rscargo clippy -p perry-codegen-wasm --tests(warnings located in the crate)emit/tests.rstests/integration/wasm/run_wasm_tests.sh04_functions,10_higher_order,19_ffi_imports)SKIP_COMPILE_GATES=1 scripts/run_lint_gates.shBrowser check: the program below compiled with
perry compile f.ts --target web -o f.html, loaded in headless Chrome (--headless=new --dump-dom) with a small script appended that selects the second option, dispatcheschangeand reads the log text:main:log=(no callback)log=picker 1I did not run the full workspace test command from the template.
Shared test helper
emit/tests.rsgainsrun_web_ui_source_then, which boots a compiled program against a small element tree (WIDGET_DOM: children, text, listeners fired bydispatch(type), descendant tag selectors forquerySelector) instead of the flat stub, so a test can build a widget, send it an event and read the DOM it produced. The existingrun_web_source_thenkeeps the flat stub. The same helper hunk is byte-identical in the sibling web-ui PRs (Toggle, Picker, Section, Image, Table), and each test sits at a different spot in the file, so the five merge in any order without conflicts; I checked this with an octopus merge of all five branches ontomain(clean, 81 tests pass).Checklist
feat:/fix:/docs:/chore:prefix convention used in the log🤖 Generated with Claude Code
https://claude.ai/code/session_01CUQanVsnitcrmYLAWWPc3p
Summary by CodeRabbit
Pickerso the callback-first form works: selecting an option now calls the callback with the chosen index.