docs+core: canonicalize interactive widget API and consolidate agent docs#235
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughStandardizes many event handler names to onChange/onPress/onClose, converts ui.button/ui.input/ui.link to single-options-object signatures, removes stack helpers (vstack/hstack/spacedVStack/spacedHStack) in favor of row/column, and updates docs, types, renderers, routing, tests, templates, and skill docs accordingly. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/jsx/src/__tests__/layout.test.tsx (1)
155-199:⚠️ Potential issue | 🟠 MajorUse
createTestRenderer()in these new test cases.These added/modified tests still rely on direct vnode
assert.deepEqualassertions instead of the required test-renderer workflow (createTestRenderer, query helpers,toText). Please align these cases with the project’s test standard for.test.tsxfiles.As per coding guidelines "Use
createTestRenderer()from the testing module for testing withviewport,findById(),findText(),findAll(), andtoText()methods".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/jsx/src/__tests__/layout.test.tsx` around lines 155 - 199, Replace the direct vnode deepEqual checks in the two tests ("Row and Column map default gap behavior" and "Grid/Row/Column normalize nullish and primitive children") with the project's test-renderer workflow: call createTestRenderer() to render the JSX (use the same components/ui helpers like Row/Column/Grid or ui.row/ui.column/ui.grid), then use the renderer query helpers (e.g., findText/findAll or toText()) to assert rendered output (for example assert the text nodes "A","B","x","1","h","2" using renderer.findText or renderer.toText()). Ensure each assertion uses the renderer instance returned by createTestRenderer rather than assert.deepEqual on vnodes.packages/jsx/src/__tests__/integration.test.tsx (1)
34-39:⚠️ Potential issue | 🟠 MajorFix Prettier failure in the factory layout block.
CI is failing on formatting in this segment; please reformat Lines 34-39 to pass the style gate.
💡 Proposed formatting fix
- ui.box({ border: "rounded", p: 1 }, [ - ui.column({ gap: 1 }, [ui.button({ id: "a", label: "Action A" }), ui.button({ id: "b", label: "Action B" })]), - ]), + ui.box({ border: "rounded", p: 1 }, [ + ui.column({ gap: 1 }, [ + ui.button({ id: "a", label: "Action A" }), + ui.button({ id: "b", label: "Action B" }), + ]), + ]),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/jsx/src/__tests__/integration.test.tsx` around lines 34 - 39, Prettier is failing due to incorrect formatting in the factory layout block that builds the vnode/factory; reformat the array/object spacing and indentation for the ui.row/ui.column/ui.button calls so the factory value matches vnode exactly—locate the factory construction (the variables named vnode and factory in the test in packages/jsx/src/__tests__/integration.test.tsx, inside the test that ends with assert.deepEqual(vnode, factory)) and adjust parentheses, commas, and indentation to follow project Prettier rules (consistent one-arg-per-line for nested UI calls) so the diff is stylistically clean.
🧹 Nitpick comments (6)
packages/core/src/layout/__tests__/layout.stability-signature.test.ts (1)
62-71: Consider renamingNOOP_RESIZEtoNOOP_CHANGEfor consistency.The constant
NOOP_RESIZEwas appropriately named when used withonResize, but now that the callback isonChange, the name is slightly misleading. A rename toNOOP_CHANGEor simplyNOOPwould better reflect its current usage.✨ Suggested rename
-const NOOP_RESIZE = (): void => {}; +const NOOP_CHANGE = (): void => {}; function splitPaneNode(children: readonly VNode[], props: Record<string, unknown> = {}): VNode { return { kind: "splitPane", props: { id: "split-pane", direction: "horizontal", sizes: Object.freeze([50, 50]), - onChange: NOOP_RESIZE, + onChange: NOOP_CHANGE, ...props, }, children: Object.freeze([...children]), } as unknown as VNode; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/layout/__tests__/layout.stability-signature.test.ts` around lines 62 - 71, The NOOP_RESIZE constant name no longer matches its usage as the onChange handler in splitPaneNode; rename the symbol NOOP_RESIZE to NOOP_CHANGE (or NOOP) and update all references, specifically the declaration and where it's assigned to the onChange prop inside splitPaneNode, to keep names consistent and clear..claude/skills/rezi-modal-dialogs/SKILL.md (1)
60-63: Add explicitonPresshandlers in the modal actions example.Both action buttons are currently inert in the snippet; adding handlers makes the example directly usable.
Proposed doc snippet adjustment
actions: [ - ui.button({ id: "confirm-cancel", label: "Cancel", intent: "secondary" }), - ui.button({ id: "confirm-ok", label: "OK", intent: "primary" }), + ui.button({ + id: "confirm-cancel", + label: "Cancel", + intent: "secondary", + onPress: () => app.update((s) => ({ ...s, showModal: false })), + }), + ui.button({ + id: "confirm-ok", + label: "OK", + intent: "primary", + onPress: handleConfirm, + }), ],🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/skills/rezi-modal-dialogs/SKILL.md around lines 60 - 63, The modal example's action buttons (ui.button with id "confirm-cancel" and "confirm-ok" inside the actions array) lack onPress handlers so they do nothing; add explicit onPress handlers to each button that invoke the modal response logic (e.g., close the modal and resolve or call the provided callback) — implement onPress for "confirm-cancel" to cancel/close the modal and for "confirm-ok" to confirm/submit and then close, ensuring the handlers reference the modal's provided close/resolve functions or the surrounding component methods.packages/core/src/widgets/__tests__/formWidgets.test.ts (1)
228-243: Rename these tests to object-only wording and drop redundant object spreads.Line 228 and Line 242 still mention shorthand overloads, but the test bodies now validate object-form only. Also,
...{ ... }is unnecessary noise here.Proposed cleanup
- test("ui.button supports shorthand and object overloads", () => { - const short = ui.button({ id: "save", label: "Save", ...{ disabled: true, px: 2 } }); + test("ui.button supports object-form props", () => { + const short = ui.button({ id: "save", label: "Save", disabled: true, px: 2 }); @@ - test("ui.input supports shorthand and object overloads", () => { - const short = ui.input({ id: "query", value: "", ...{ disabled: true } }); + test("ui.input supports object-form props", () => { + const short = ui.input({ id: "query", value: "", disabled: true });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/widgets/__tests__/formWidgets.test.ts` around lines 228 - 243, Rename the two tests whose titles read "ui.button supports shorthand and object overloads" and "ui.input supports shorthand and object overloads" to reflect that they only validate the object form (e.g., "ui.button supports object overload" and "ui.input supports object overload"), and remove the redundant object spread syntax in the test calls to ui.button and ui.input (drop the unnecessary ...{ disabled: true, px: 2 } and ...{ disabled: true } spreads), leaving the direct object literals passed to ui.button and ui.input and keeping assertions unchanged.packages/core/src/renderer/__tests__/inputRecipeRendering.test.ts (1)
20-20: Simplify redundant object spread inui.inputprops.
...{ placeholder: "Name" }is unnecessary noise in these tests.♻️ Suggested cleanup
- ui.row({ height: 3, items: "stretch" }, [ui.input({ id: "name", value: "", ...{ placeholder: "Name" } })]), + ui.row({ height: 3, items: "stretch" }, [ui.input({ id: "name", value: "", placeholder: "Name" })]), - ui.row({ height: 3, items: "stretch" }, [ui.input({ id: "legacy", value: "", ...{ placeholder: "Name" } })]), + ui.row({ height: 3, items: "stretch" }, [ui.input({ id: "legacy", value: "", placeholder: "Name" })]), - ui.column({ width: 20, items: "stretch" }, [ui.input({ id: "i-md", value: "", ...{ placeholder: "Name" } })]), + ui.column({ width: 20, items: "stretch" }, [ui.input({ id: "i-md", value: "", placeholder: "Name" })]),Also applies to: 36-36, 66-66
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/renderer/__tests__/inputRecipeRendering.test.ts` at line 20, The test contains redundant object spread usage in the ui.input properties—replace patterns like ...{ placeholder: "Name" } with the direct property placeholder: "Name" in the ui.input call inside the ui.row (and the two other similar ui.input usages in the same test file), ensuring you update each occurrence so props are passed directly rather than via a needless spread object.AGENTS.md (1)
218-228: Consider varying sentence starters for readability.The verification checklist items all begin with "Confirm". While functional, varying the phrasing could improve readability (e.g., "Verify", "Check", "Ensure", "Validate").
Suggested rewording
### Agent 1 — Accuracy Checker -- Confirm file paths in docs exist. -- Confirm signatures match exports in `packages/core/src/index.ts`. -- Confirm prop/callback names match `packages/core/src/widgets/types.ts`. -- Confirm examples compile against current API shape. +- Verify file paths in docs exist. +- Check signatures match exports in `packages/core/src/index.ts`. +- Validate prop/callback names match `packages/core/src/widgets/types.ts`. +- Ensure examples compile against current API shape. ### Agent 2 — Completeness Checker -- Confirm no critical exports are missing from docs. -- Confirm canonical APIs are represented (no stale alternatives). -- Confirm guidance matches template patterns in `packages/create-rezi/templates/`. -- Confirm constraints and limits referenced in docs match code constants. +- Check no critical exports are missing from docs. +- Verify canonical APIs are represented (no stale alternatives). +- Ensure guidance matches template patterns in `packages/create-rezi/templates/`. +- Validate constraints and limits referenced in docs match code constants.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@AGENTS.md` around lines 218 - 228, Update the repeated "Confirm" sentence starters in the AGENTS.md checklist to improve readability by replacing some occurrences with synonyms (e.g., use "Verify", "Ensure", "Check", "Validate") while preserving the original meaning and intent; specifically modify the bullets that reference `packages/core/src/index.ts`, `packages/core/src/widgets/types.ts`, `packages/create-rezi/templates/`, and the "Agent 2 — Completeness Checker" section so the checklist reads more varied but still clearly maps to those files and checks.packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts (1)
104-104: Simplify object spread syntax.The
...{ id: "lnk" }spread is unnecessarily complex when you can includeiddirectly in the props object.Suggested simplification
- { name: "link", vnode: ui.link({ url: "https://example.com", label: "Example", ...{ id: "lnk" } }) }, + { name: "link", vnode: ui.link({ url: "https://example.com", label: "Example", id: "lnk" }) },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts` at line 104, The test uses an unnecessary object spread in the vnode creation for the "link" widget; update the vnode call that uses ui.link({ url: "https://example.com", label: "Example", ...{ id: "lnk" } }) to pass id directly in the props object (e.g., include id: "lnk" alongside url and label) so the ui.link vnode creation and the test line with name: "link" are simplified and equivalent without the spread.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.claude/skills/rezi-forms/SKILL.md:
- Around line 55-59: The action row currently binds three buttons to
form.handleSubmit (ui.actions with ui.button id "save", "approve", "review"),
which violates the cancel-first/primary-last convention; update the ui.actions
call to include a cancel button first (e.g., a ui.button with id "cancel" that
calls a cancel/reset/navigation handler) and a single primary submit button last
(keep the "save" button using form.handleSubmit), and move any "approve" /
"review" flows out of the primary submit (either convert them to non-submit
actions with their own handlers or into a separate menu) so only one
submit-bound button remains and ordering follows cancel then primary.
In @.codex/skills/rezi-forms/SKILL.md:
- Around line 55-59: The form actions currently use three submit-style buttons
(ui.button with ids "save", "approve", "review") and no cancel action; update
the ui.actions invocation to follow the cancel-first / primary-submit-last
convention by adding a cancel button as the first entry (e.g., id "cancel") and
reorder buttons so the primary submit (id "save") is last; convert "approve" and
"review" to secondary/neutral actions or move them before the primary submit as
non-primary intents to avoid multiple primary-submit buttons.
In `@CLAUDE.md`:
- Line 400: The table cells for `toolApprovalDialog` (the
`ui.toolApprovalDialog({ id, request, open, onPress, onClose, ... })` row)
contain unescaped pipe characters in the callback signature `onPress: (action:
"allow" | "deny") => void`; update both occurrences (lines referenced around the
`toolApprovalDialog` row and the other instance at the second occurrence) to
escape the pipe characters so the Markdown table parses correctly (e.g., replace
`|` with `\|` or `|` inside the callback signature), ensuring the symbol
`onPress` and the `ui.toolApprovalDialog` signature remain unchanged except for
the escaped pipe.
In `@packages/core/src/__tests__/stress/fuzz.random-events.test.ts`:
- Around line 510-513: Reformat the widget block containing ui.row, ui.button,
and ui.input so it matches Prettier formatting: ensure each array element is on
its own line with proper indentation, include trailing commas where appropriate,
and align the closing brackets and parentheses; specifically update the block
around ui.row({ gap: 1 }, [ui.button({ id: "btn-main", label: "Main" }),
ui.button({ id: "btn-aux", label: "Aux" })]), ui.input({ id: "inp-main", value:
state.mainValue }), ui.input({ id: "inp-aux", value: state.auxValue }), to use
multiline entries and consistent comma placement to satisfy the formatter.
In `@packages/core/src/layout/__tests__/layout.overflow-hidden.test.ts`:
- Around line 215-217: The failing CI check is a Prettier formatting issue in
the test hunk using ui.row/ui.button and mustLayout; reformat the block to match
the project's Prettier rules (e.g., run the repo's Prettier command or apply the
project's VSCode formatting) so the lines for const root and const tree conform
to the code style; locate the usages of ui.row, ui.button, and mustLayout in
layout.overflow-hidden.test.ts and save the file after formatting to unblock CI.
In `@packages/core/src/renderer/__tests__/inputRecipeRendering.test.ts`:
- Around line 20-22: Prettier formatting is failing for the test block
containing ui.row and ui.input; reformat the code in this file
(packages/core/src/renderer/__tests__/inputRecipeRendering.test.ts) so it
adheres to the project's Prettier rules—run your formatter or `prettier --write`
on the file (or re-run your editor's format) to normalize the ui.row({ height:
3, items: "stretch" }, [ui.input({ id: "name", value: "", ...{ placeholder:
"Name" } })]), { viewport: { cols: 40, rows: 5 }, theme: dsTheme } block and
commit the formatted result.
In `@packages/core/src/ui/__tests__/designSystem.renderer.test.ts`:
- Around line 63-64: Reformat the ui.row call that contains the stretched input
to satisfy the formatter: rewrite the ui.row({...}, [...]) expression so its
object and array arguments are split across lines cleanly (adjusting spacing
around the object literal and the ui.input call) — specifically update the
ui.row({ height: 3, items: "stretch" }, [ui.input({ id: "name", value: "", ...{
placeholder: "Name" } })]) expression (the ui.row and ui.input invocation) to a
properly formatted multi-line form that biome accepts.
In `@packages/core/src/widgets/__tests__/basicWidgets.render.test.ts`:
- Line 536: The call expression to renderBytesV3 with ui.link(...) is too long
for Prettier; reformat the invocation to multiple lines so it adheres to
Prettier rules—break the arguments across lines and indent them properly (e.g.,
place renderBytesV3( on its own line, put ui.link({ url: "...", label: "..." })
on the next line and the options object { cols: 40, rows: 4 } on a following
line) so the call to renderBytesV3 and the nested ui.link call are each wrapped
and aligned for Prettier to accept.
In `@packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts`:
- Line 104: The failing test is due to Prettier formatting on the test vector
that uses ui.link in widgetRenderSmoke.test.ts; fix by running the project's
formatter (e.g., run prettier --write) or manually reformat the line containing
{ name: "link", vnode: ui.link({ url: "https://example.com", label: "Example",
...{ id: "lnk" } }) } so it matches the repo's Prettier rules; ensure the
ui.link(...) call and object spread formatting match surrounding test cases so
CI formatting checks pass.
In `@packages/jsx/src/__tests__/jsx-runtime.test.tsx`:
- Around line 30-31: Prettier flagged formatting in the test assertion using
assert.deepEqual with vnode and ui.column/ui.text/ui.button; reformat the
assertion to match the project's Prettier rules (run prettier --write on
packages/jsx/src/__tests__/jsx-runtime.test.tsx or adjust the line so
spacing/line breaks match the formatter) so the test file's
assert.deepEqual(vnode, ui.column({ gap: 1 }, [ui.text("A"), ui.button({ id:
"x", label: "X" })])); conforms to CI formatting.
In `@packages/jsx/src/__tests__/parity.test.tsx`:
- Around line 190-192: The test file has a Prettier formatting violation around
the ui.splitPane call (symbols: ui.splitPane, ui.resizablePanel, ui.text); fix
by running the project Prettier formatter (e.g., prettier --write) or applying
the repo's formatting rules to that block so the splitPane/resizablePanel
invocation is formatted according to CI rules, then re-run lint/format check and
commit the formatted file.
---
Outside diff comments:
In `@packages/jsx/src/__tests__/integration.test.tsx`:
- Around line 34-39: Prettier is failing due to incorrect formatting in the
factory layout block that builds the vnode/factory; reformat the array/object
spacing and indentation for the ui.row/ui.column/ui.button calls so the factory
value matches vnode exactly—locate the factory construction (the variables named
vnode and factory in the test in
packages/jsx/src/__tests__/integration.test.tsx, inside the test that ends with
assert.deepEqual(vnode, factory)) and adjust parentheses, commas, and
indentation to follow project Prettier rules (consistent one-arg-per-line for
nested UI calls) so the diff is stylistically clean.
In `@packages/jsx/src/__tests__/layout.test.tsx`:
- Around line 155-199: Replace the direct vnode deepEqual checks in the two
tests ("Row and Column map default gap behavior" and "Grid/Row/Column normalize
nullish and primitive children") with the project's test-renderer workflow: call
createTestRenderer() to render the JSX (use the same components/ui helpers like
Row/Column/Grid or ui.row/ui.column/ui.grid), then use the renderer query
helpers (e.g., findText/findAll or toText()) to assert rendered output (for
example assert the text nodes "A","B","x","1","h","2" using renderer.findText or
renderer.toText()). Ensure each assertion uses the renderer instance returned by
createTestRenderer rather than assert.deepEqual on vnodes.
---
Nitpick comments:
In @.claude/skills/rezi-modal-dialogs/SKILL.md:
- Around line 60-63: The modal example's action buttons (ui.button with id
"confirm-cancel" and "confirm-ok" inside the actions array) lack onPress
handlers so they do nothing; add explicit onPress handlers to each button that
invoke the modal response logic (e.g., close the modal and resolve or call the
provided callback) — implement onPress for "confirm-cancel" to cancel/close the
modal and for "confirm-ok" to confirm/submit and then close, ensuring the
handlers reference the modal's provided close/resolve functions or the
surrounding component methods.
In `@AGENTS.md`:
- Around line 218-228: Update the repeated "Confirm" sentence starters in the
AGENTS.md checklist to improve readability by replacing some occurrences with
synonyms (e.g., use "Verify", "Ensure", "Check", "Validate") while preserving
the original meaning and intent; specifically modify the bullets that reference
`packages/core/src/index.ts`, `packages/core/src/widgets/types.ts`,
`packages/create-rezi/templates/`, and the "Agent 2 — Completeness Checker"
section so the checklist reads more varied but still clearly maps to those files
and checks.
In `@packages/core/src/layout/__tests__/layout.stability-signature.test.ts`:
- Around line 62-71: The NOOP_RESIZE constant name no longer matches its usage
as the onChange handler in splitPaneNode; rename the symbol NOOP_RESIZE to
NOOP_CHANGE (or NOOP) and update all references, specifically the declaration
and where it's assigned to the onChange prop inside splitPaneNode, to keep names
consistent and clear.
In `@packages/core/src/renderer/__tests__/inputRecipeRendering.test.ts`:
- Line 20: The test contains redundant object spread usage in the ui.input
properties—replace patterns like ...{ placeholder: "Name" } with the direct
property placeholder: "Name" in the ui.input call inside the ui.row (and the two
other similar ui.input usages in the same test file), ensuring you update each
occurrence so props are passed directly rather than via a needless spread
object.
In `@packages/core/src/widgets/__tests__/formWidgets.test.ts`:
- Around line 228-243: Rename the two tests whose titles read "ui.button
supports shorthand and object overloads" and "ui.input supports shorthand and
object overloads" to reflect that they only validate the object form (e.g.,
"ui.button supports object overload" and "ui.input supports object overload"),
and remove the redundant object spread syntax in the test calls to ui.button and
ui.input (drop the unnecessary ...{ disabled: true, px: 2 } and ...{ disabled:
true } spreads), leaving the direct object literals passed to ui.button and
ui.input and keeping assertions unchanged.
In `@packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts`:
- Line 104: The test uses an unnecessary object spread in the vnode creation for
the "link" widget; update the vnode call that uses ui.link({ url:
"https://example.com", label: "Example", ...{ id: "lnk" } }) to pass id directly
in the props object (e.g., include id: "lnk" alongside url and label) so the
ui.link vnode creation and the test line with name: "link" are simplified and
equivalent without the spread.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (91)
.claude/skills/rezi-create-screen/SKILL.md.claude/skills/rezi-forms/SKILL.md.claude/skills/rezi-modal-dialogs/SKILL.md.codex/skills/rezi-create-screen/SKILL.md.codex/skills/rezi-forms/SKILL.md.codex/skills/rezi-modal-dialogs/SKILL.mdAGENTS.mdCLAUDE.mdREADME.mddocs/getting-started/jsx.mddocs/guide/mouse-support.mddocs/index.mddocs/migration/ink-to-rezi.mddocs/packages/core.mddocs/recipes/form-validation.mddocs/styling/focus-styles.mddocs/widgets/catalog.jsondocs/widgets/command-palette.mddocs/widgets/file-picker.mddocs/widgets/file-tree-explorer.mddocs/widgets/grid.mddocs/widgets/index.mddocs/widgets/link.mddocs/widgets/logs-console.mddocs/widgets/split-pane.mddocs/widgets/stack.mddocs/widgets/toast.mddocs/widgets/tool-approval-dialog.mddocs/widgets/tree.mdpackages/core/src/__tests__/integration/integration.dashboard.test.tspackages/core/src/__tests__/integration/integration.file-manager.test.tspackages/core/src/__tests__/integration/integration.reflow.test.tspackages/core/src/__tests__/stress/fuzz.random-events.test.tspackages/core/src/app/__tests__/commandPaletteRouting.test.tspackages/core/src/app/__tests__/filePickerRouting.contracts.test.tspackages/core/src/app/__tests__/fileTreeExplorer.contextMenu.test.tspackages/core/src/app/__tests__/shortcutEnforcement.test.tspackages/core/src/app/__tests__/widgetRenderer.integration.test.tspackages/core/src/app/widgetRenderer.tspackages/core/src/app/widgetRenderer/commandPaletteRouting.tspackages/core/src/app/widgetRenderer/filePickerRouting.tspackages/core/src/app/widgetRenderer/keyboardRouting.tspackages/core/src/app/widgetRenderer/mouseRouting.tspackages/core/src/app/widgetRenderer/toolApprovalRouting.tspackages/core/src/layout/__tests__/layout.overflow-hidden.test.tspackages/core/src/layout/__tests__/layout.overflow-scroll.test.tspackages/core/src/layout/__tests__/layout.overlay-constraints.test.tspackages/core/src/layout/__tests__/layout.perf-invariants.test.tspackages/core/src/layout/__tests__/layout.stability-coverage.test.tspackages/core/src/layout/__tests__/layout.stability-signature.test.tspackages/core/src/layout/__tests__/splitPaneCollapse.test.tspackages/core/src/layout/__tests__/sweep.robustness.test.tspackages/core/src/renderer/__tests__/inputRecipeRendering.test.tspackages/core/src/renderer/__tests__/renderer.damage.test.tspackages/core/src/runtime/__tests__/duplicateIdFatal.test.tspackages/core/src/runtime/__tests__/overlayUnification.test.tspackages/core/src/runtime/__tests__/widgetMeta.test.tspackages/core/src/ui/__tests__/designSystem.renderer.test.tspackages/core/src/widgets/__tests__/basicWidgets.render.test.tspackages/core/src/widgets/__tests__/basicWidgets.test.tspackages/core/src/widgets/__tests__/collections.test.tspackages/core/src/widgets/__tests__/compositionWidgets.test.tspackages/core/src/widgets/__tests__/containers.test.tspackages/core/src/widgets/__tests__/editors.test.tspackages/core/src/widgets/__tests__/filesWidgets.test.tspackages/core/src/widgets/__tests__/formWidgets.test.tspackages/core/src/widgets/__tests__/infoWidgets.test.tspackages/core/src/widgets/__tests__/overlays.test.tspackages/core/src/widgets/__tests__/renderer.regressions.test.tspackages/core/src/widgets/__tests__/splitPane.nested.test.tspackages/core/src/widgets/__tests__/vnode.children-filter.test.tspackages/core/src/widgets/__tests__/vnode.factory.test.tspackages/core/src/widgets/__tests__/widgetRenderSmoke.test.tspackages/core/src/widgets/types.tspackages/core/src/widgets/ui.tspackages/create-rezi/templates/cli-tool/src/screens/logs.tspackages/create-rezi/templates/starship/src/screens/comms.tspackages/create-rezi/templates/starship/src/screens/engineering.tspackages/create-rezi/templates/starship/src/screens/shell.tspackages/jsx/src/__tests__/advanced.test.tsxpackages/jsx/src/__tests__/data.test.tsxpackages/jsx/src/__tests__/integration.test.tsxpackages/jsx/src/__tests__/interactive.test.tsxpackages/jsx/src/__tests__/jsx-runtime.test.tsxpackages/jsx/src/__tests__/layout.test.tsxpackages/jsx/src/__tests__/parity.test.tsxpackages/jsx/src/__tests__/text.test.tsxpackages/jsx/src/components.tspackages/jsx/src/createElement.tspackages/jsx/src/index.tspackages/jsx/src/types.ts
💤 Files with no reviewable changes (5)
- packages/jsx/src/types.ts
- packages/jsx/src/components.ts
- docs/getting-started/jsx.md
- packages/jsx/src/createElement.ts
- packages/jsx/src/index.ts
packages/core/src/layout/__tests__/layout.overflow-hidden.test.ts
Outdated
Show resolved
Hide resolved
packages/core/src/widgets/__tests__/basicWidgets.render.test.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts (1)
104-107: Simplify the spread syntax to a direct property.The
...{ id: "lnk" }spread is equivalent toid: "lnk". This appears to be a refactoring artifact.✨ Suggested simplification
{ name: "link", - vnode: ui.link({ url: "https://example.com", label: "Example", ...{ id: "lnk" } }), + vnode: ui.link({ url: "https://example.com", label: "Example", id: "lnk" }), },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts` around lines 104 - 107, In the test case item with name "link" update the vnode creation to remove the unnecessary object spread; inside the ui.link(...) call replace the spread ...{ id: "lnk" } with a direct property id: "lnk" so the vnode props are passed as url: "https://example.com", label: "Example", id: "lnk" (locate the object with name: "link" and the vnode: ui.link(...) to make the change).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts`:
- Around line 104-107: In the test case item with name "link" update the vnode
creation to remove the unnecessary object spread; inside the ui.link(...) call
replace the spread ...{ id: "lnk" } with a direct property id: "lnk" so the
vnode props are passed as url: "https://example.com", label: "Example", id:
"lnk" (locate the object with name: "link" and the vnode: ui.link(...) to make
the change).
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
packages/core/src/__tests__/stress/fuzz.random-events.test.tspackages/core/src/layout/__tests__/layout.overflow-hidden.test.tspackages/core/src/renderer/__tests__/inputRecipeRendering.test.tspackages/core/src/ui/__tests__/designSystem.renderer.test.tspackages/core/src/widgets/__tests__/basicWidgets.render.test.tspackages/core/src/widgets/__tests__/widgetRenderSmoke.test.tspackages/jsx/src/__tests__/integration.test.tsxpackages/jsx/src/__tests__/jsx-runtime.test.tsxpackages/jsx/src/__tests__/parity.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/core/src/ui/tests/designSystem.renderer.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
CLAUDE.md (1)
495-495:⚠️ Potential issue | 🟡 MinorEscape pipe character in callback signature to fix table parsing.
Line 495 contains an unescaped pipe (
|) inside the callback signature(action: "allow" | "deny"), which breaks markdown table rendering. Line 400 was already fixed, but this occurrence in the Callback Quick Reference table still needs the same fix.🛠️ Proposed fix
-| `toolApprovalDialog` | `onPress` | `(action: "allow" | "deny") => void` | Yes | +| `toolApprovalDialog` | `onPress` | `(action: "allow" \| "deny") => void` | Yes |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@CLAUDE.md` at line 495, The table cell for the `toolApprovalDialog` callback contains an unescaped pipe in the signature `onPress` (the callback `(action: "allow" | "deny") => void`) which breaks Markdown table parsing; update the callback signature in that table to escape the pipe as `\|` (i.e., change `(action: "allow" | "deny") => void` to `(action: "allow" \| "deny") => void`) for the `toolApprovalDialog` / `onPress` entry so the table renders correctly.
🧹 Nitpick comments (3)
.claude/skills/rezi-forms/SKILL.md (1)
63-63: Clarifyform.bind()return shape vs example usage to avoididambiguity.You document that
form.bind()returnsid, but examples also pass explicitidbefore spreading...form.bind(...). That can implyidoverride behavior and may confuse readers. Consider either removingidfrom the documented bind shape (if not guaranteed), or updating examples to rely on one source of truth.Suggested doc tweak
-2. **Bind fields** using `form.bind("fieldName")` — returns object-form input props (`id`, `value`, `onInput`, `onBlur`, `disabled`) +2. **Bind fields** using `form.bind("fieldName")` — returns object-form input props (`value`, `onInput`, `onBlur`, `disabled`) + - If you need a custom `id`, pass it explicitly in `ui.input(...)`.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/skills/rezi-forms/SKILL.md at line 63, The documentation currently states that form.bind("fieldName") returns an object that includes id, but examples also pass an explicit id before spreading ...form.bind(...), causing ambiguity; update the SKILL.md text around form.bind to either (A) remove id from the documented return shape and state that callers must provide id themselves, or (B) keep id in the return shape and change all examples to stop passing a separate id (use only ...form.bind("fieldName") for attributes), and add one sentence clarifying whether an explicit id passed before/after spreading overrides the bind-provided id; refer to the form.bind("fieldName") mention and the example snippets to locate the lines to change..codex/skills/rezi-forms/SKILL.md (1)
69-73: Preferui.actions([...])for this multi-button side-action example.Since this example shows a button group, wrapping it in
ui.actions([...])would keep it aligned with the same layout convention used elsewhere in this skill.Based on learnings: "Place buttons in
ui.actions([...])for right-aligned button rows."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.codex/skills/rezi-forms/SKILL.md around lines 69 - 73, Replace the inline ui.button calls with a right-aligned action group by wrapping the buttons in ui.actions([...]) instead of calling ui.button(...) separately; specifically, take the two buttons (ui.button calls with id "approve" and "review", intents "success" and "warning" and handlers handleApprove and handleReview) and move them into a single ui.actions([...]) call so they render as a grouped, right-aligned button row consistent with the rest of the skill.packages/core/src/widgets/__tests__/formWidgets.test.ts (1)
228-254: Consider updating variable names now that shorthand overloads are removed.The variable names
shortandfullare remnants from when the tests verified both positional shorthand and object-form overloads. Now that object-form is the only API, these names are slightly misleading—both calls are object-form, just with different props.Similarly, the test descriptions "supports object props" imply alternative calling conventions exist. Consider renaming to reflect the canonical API (e.g., "ui.button creates button VNode with props").
✏️ Suggested naming improvements
- test("ui.button supports object props", () => { - const short = ui.button({ id: "save", label: "Save", disabled: true, px: 2 }); - assert.equal(short.kind, "button"); - assert.deepEqual(short.props, { id: "save", label: "Save", disabled: true, px: 2 }); + test("ui.button creates button VNode", () => { + const disabledBtn = ui.button({ id: "save", label: "Save", disabled: true, px: 2 }); + assert.equal(disabledBtn.kind, "button"); + assert.deepEqual(disabledBtn.props, { id: "save", label: "Save", disabled: true, px: 2 }); - const full = ui.button({ + const styledBtn = ui.button({ id: "cancel", label: "Cancel", style: { dim: true }, }); - assert.equal(full.kind, "button"); - assert.deepEqual(full.props, { id: "cancel", label: "Cancel", style: { dim: true } }); + assert.equal(styledBtn.kind, "button"); + assert.deepEqual(styledBtn.props, { id: "cancel", label: "Cancel", style: { dim: true } }); }); - test("ui.input supports object props", () => { - const short = ui.input({ id: "query", value: "", disabled: true }); - assert.equal(short.kind, "input"); - assert.deepEqual(short.props, { id: "query", value: "", disabled: true }); + test("ui.input creates input VNode", () => { + const disabledInput = ui.input({ id: "query", value: "", disabled: true }); + assert.equal(disabledInput.kind, "input"); + assert.deepEqual(disabledInput.props, { id: "query", value: "", disabled: true }); - const full = ui.input({ + const styledInput = ui.input({ id: "path", value: "/tmp", style: { italic: true }, }); - assert.equal(full.kind, "input"); - assert.deepEqual(full.props, { id: "path", value: "/tmp", style: { italic: true } }); + assert.equal(styledInput.kind, "input"); + assert.deepEqual(styledInput.props, { id: "path", value: "/tmp", style: { italic: true } }); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/widgets/__tests__/formWidgets.test.ts` around lines 228 - 254, Rename misleading test variables and update descriptions to reflect the current object-only API: in the tests for ui.button and ui.input (the test cases referencing variables named short and full), replace those variable names with clearer names like btnA/btnB or buttonPrimary/buttonSecondary and update the test titles from "supports object props" to something like "ui.button creates button VNode with props" and "ui.input creates input VNode with props" so both uses clearly convey they are object-form calls; keep assertions against .kind and .props unchanged (references: ui.button, ui.input, short, full).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.codex/skills/rezi-forms/SKILL.md:
- Line 63: The documentation currently lists form.bind("fieldName") as returning
an id but examples also pass id explicitly; pick one consistent pattern — either
remove "id" from the returned props list on the Bind fields bullet (so
form.bind() returns value, onInput, onBlur, disabled only) or update the
examples to stop passing explicit id and rely on the id returned by form.bind().
Update the text near the Bind fields bullet and any examples referencing
form.bind() (search for form.bind and examples in SKILL.md) to reflect the
chosen pattern consistently.
---
Duplicate comments:
In `@CLAUDE.md`:
- Line 495: The table cell for the `toolApprovalDialog` callback contains an
unescaped pipe in the signature `onPress` (the callback `(action: "allow" |
"deny") => void`) which breaks Markdown table parsing; update the callback
signature in that table to escape the pipe as `\|` (i.e., change `(action:
"allow" | "deny") => void` to `(action: "allow" \| "deny") => void`) for the
`toolApprovalDialog` / `onPress` entry so the table renders correctly.
---
Nitpick comments:
In @.claude/skills/rezi-forms/SKILL.md:
- Line 63: The documentation currently states that form.bind("fieldName")
returns an object that includes id, but examples also pass an explicit id before
spreading ...form.bind(...), causing ambiguity; update the SKILL.md text around
form.bind to either (A) remove id from the documented return shape and state
that callers must provide id themselves, or (B) keep id in the return shape and
change all examples to stop passing a separate id (use only
...form.bind("fieldName") for attributes), and add one sentence clarifying
whether an explicit id passed before/after spreading overrides the bind-provided
id; refer to the form.bind("fieldName") mention and the example snippets to
locate the lines to change.
In @.codex/skills/rezi-forms/SKILL.md:
- Around line 69-73: Replace the inline ui.button calls with a right-aligned
action group by wrapping the buttons in ui.actions([...]) instead of calling
ui.button(...) separately; specifically, take the two buttons (ui.button calls
with id "approve" and "review", intents "success" and "warning" and handlers
handleApprove and handleReview) and move them into a single ui.actions([...])
call so they render as a grouped, right-aligned button row consistent with the
rest of the skill.
In `@packages/core/src/widgets/__tests__/formWidgets.test.ts`:
- Around line 228-254: Rename misleading test variables and update descriptions
to reflect the current object-only API: in the tests for ui.button and ui.input
(the test cases referencing variables named short and full), replace those
variable names with clearer names like btnA/btnB or
buttonPrimary/buttonSecondary and update the test titles from "supports object
props" to something like "ui.button creates button VNode with props" and
"ui.input creates input VNode with props" so both uses clearly convey they are
object-form calls; keep assertions against .kind and .props unchanged
(references: ui.button, ui.input, short, full).
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.claude/skills/rezi-forms/SKILL.md.claude/skills/rezi-modal-dialogs/SKILL.md.codex/skills/rezi-forms/SKILL.md.codex/skills/rezi-modal-dialogs/SKILL.mdAGENTS.mdCLAUDE.mdpackages/core/src/layout/__tests__/layout.stability-signature.test.tspackages/core/src/renderer/__tests__/inputRecipeRendering.test.tspackages/core/src/widgets/__tests__/formWidgets.test.tspackages/core/src/widgets/__tests__/widgetRenderSmoke.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/core/src/renderer/tests/inputRecipeRendering.test.ts
- packages/core/src/layout/tests/layout.stability-signature.test.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/core/src/layout/__tests__/layout.perf.test.ts (1)
97-97: Please keep frame-audit evidence alongside future perf-threshold bumps.When thresholds are relaxed, attach
REZI_FRAME_AUDIToutput/report in PR validation notes so regressions remain visible.Based on learnings: For rendering/layout/theme regressions, validate with live PTY and collect frame audit evidence via
REZI_FRAME_AUDITlogs andnode scripts/frame-audit-report.mjs.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/layout/__tests__/layout.perf.test.ts` at line 97, The PR relaxes the PERF threshold constant REALISTIC_FRAME_BUDGET_MS in layout.perf.test.ts; when increasing this value, ensure you attach frame-audit evidence to the PR by running the live PTY validation and collecting REZI_FRAME_AUDIT logs and the frame-audit report (run node scripts/frame-audit-report.mjs) and include both the REZI_FRAME_AUDIT output and the generated report in the PR validation notes so regressions remain visible; mention which environments (IS_WINDOWS / IS_CI) were used when collecting the evidence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/core/src/layout/__tests__/layout.perf.test.ts`:
- Line 97: The PR relaxes the PERF threshold constant REALISTIC_FRAME_BUDGET_MS
in layout.perf.test.ts; when increasing this value, ensure you attach
frame-audit evidence to the PR by running the live PTY validation and collecting
REZI_FRAME_AUDIT logs and the frame-audit report (run node
scripts/frame-audit-report.mjs) and include both the REZI_FRAME_AUDIT output and
the generated report in the PR validation notes so regressions remain visible;
mention which environments (IS_WINDOWS / IS_CI) were used when collecting the
evidence.
There was a problem hiding this comment.
🧹 Nitpick comments (3)
.claude/skills/rezi-forms/SKILL.md (1)
69-73: Optional doc consistency tweak: show side actions as an action group when presented together.If these two side actions are meant to be shown together in a row, consider documenting them inside
ui.actions([...])to avoid mixed layout patterns across examples.♻️ Suggested doc snippet
- ui.button({ id: "approve", label: "Approve", intent: "success", onPress: handleApprove }); - ui.button({ id: "review", label: "Needs Review", intent: "warning", onPress: handleReview }); + ui.actions([ + ui.button({ id: "approve", label: "Approve", intent: "success", onPress: handleApprove }), + ui.button({ id: "review", label: "Needs Review", intent: "warning", onPress: handleReview }), + ]);Based on learnings: "Button groups MUST use
ui.actions([...])for right-aligned layout."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/skills/rezi-forms/SKILL.md around lines 69 - 73, The side-action buttons shown with ui.button (id "approve" / handler handleApprove and id "review" / handler handleReview) should be documented as a grouped action using ui.actions([...]) when they are intended to appear together; update the example to place those two actions inside a single ui.actions call so the layout is consistent and right-aligned rather than showing separate ui.button calls..codex/skills/rezi-forms/SKILL.md (2)
55-58: Avoid documenting a no-op Cancel action.
onPress: () => {}for Cancel can be copied into production and create a dead control. Prefer wiring a realonCancelcallback in the example.Suggested doc snippet adjustment
-const MyForm = defineWidget<{ onSubmit: (v: Values) => void }>((props, ctx) => { +const MyForm = defineWidget<{ onSubmit: (v: Values) => void; onCancel: () => void }>((props, ctx) => { @@ ui.actions([ - ui.button({ id: "cancel", label: "Cancel", intent: "secondary", onPress: () => {} }), + ui.button({ id: "cancel", label: "Cancel", intent: "secondary", onPress: props.onCancel }), ui.button({ id: "save", label: "Save", intent: "primary", onPress: form.handleSubmit }), ]),Based on learnings: "End forms with
ui.actions([cancelBtn, submitBtn])— cancel first, primary submit last."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.codex/skills/rezi-forms/SKILL.md around lines 55 - 58, The example documents a no-op Cancel button (ui.button with id "cancel" and onPress: () => {}) which can be copy-pasted into production; replace the empty handler with a real cancellation callback prop (e.g., an onCancel function) and wire it into the cancel button’s onPress to call onCancel; keep the save button using form.handleSubmit and ensure actions are ordered cancel first, submit last (ui.actions([...])) so consumers see a working cancel control instead of a noop.
69-73: Group side-action buttons withui.actions(...)for pattern consistency.The snippet currently models a raw button list. Prefer showing the canonical grouped action pattern.
Suggested doc snippet adjustment
- ui.button({ id: "approve", label: "Approve", intent: "success", onPress: handleApprove }); - ui.button({ id: "review", label: "Needs Review", intent: "warning", onPress: handleReview }); + ui.actions([ + ui.button({ id: "approve", label: "Approve", intent: "success", onPress: handleApprove }), + ui.button({ id: "review", label: "Needs Review", intent: "warning", onPress: handleReview }), + ]);Based on learnings: "Button groups MUST use
ui.actions([...])for right-aligned layout."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.codex/skills/rezi-forms/SKILL.md around lines 69 - 73, The snippet uses raw ui.button calls for side actions (ui.button with ids "approve" and "review" and handlers handleApprove/handleReview) but policy requires grouping side-action buttons with ui.actions([...]) for right-aligned layout; refactor the two ui.button calls into a single ui.actions call that contains those button definitions (preserving id, label, intent, and onPress references) so the buttons are rendered as a grouped/action set rather than individual raw buttons.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.claude/skills/rezi-forms/SKILL.md:
- Around line 69-73: The side-action buttons shown with ui.button (id "approve"
/ handler handleApprove and id "review" / handler handleReview) should be
documented as a grouped action using ui.actions([...]) when they are intended to
appear together; update the example to place those two actions inside a single
ui.actions call so the layout is consistent and right-aligned rather than
showing separate ui.button calls.
In @.codex/skills/rezi-forms/SKILL.md:
- Around line 55-58: The example documents a no-op Cancel button (ui.button with
id "cancel" and onPress: () => {}) which can be copy-pasted into production;
replace the empty handler with a real cancellation callback prop (e.g., an
onCancel function) and wire it into the cancel button’s onPress to call
onCancel; keep the save button using form.handleSubmit and ensure actions are
ordered cancel first, submit last (ui.actions([...])) so consumers see a working
cancel control instead of a noop.
- Around line 69-73: The snippet uses raw ui.button calls for side actions
(ui.button with ids "approve" and "review" and handlers
handleApprove/handleReview) but policy requires grouping side-action buttons
with ui.actions([...]) for right-aligned layout; refactor the two ui.button
calls into a single ui.actions call that contains those button definitions
(preserving id, label, intent, and onPress references) so the buttons are
rendered as a grouped/action set rather than individual raw buttons.
Summary
This PR delivers the docs consolidation and API canonicalization work for Rezi.
Source API canonicalization
ui.button(...)is now object-form onlyui.input(...)is now object-form onlyui.link(...)is now object-form onlyvstack,hstack,spacedVStack,spacedHStackrow/columnonToggle->onChangeonActivate->onPressonQueryChange->onChangeonDismiss->onCloseDocumentation overhaul
CLAUDE.mdinto a canonical reference for:successandwarning)ResponsiveValuemaps +fluid(...)) in layout baselineui.tsAGENTS.mdso shared guidance points toCLAUDE.md, keeping agent-specific workflow content only.rezi-create-screen,rezi-forms,rezi-modal-dialogs) in both.claude/skillsand.codex/skills.Why
The goal is to give agents and contributors one unambiguous canonical API surface:
Validation
npm run build -- --forcenode scripts/run-tests.mjs48580Additional doc/API checks run during implementation:
ui.button("...")/ui.input("...")usage in package sourcesui.tsdocs canonical sectionstypes.ts(onToggle,onActivate,onDismiss,onQueryChangeremoved)Summary by CodeRabbit
New Features
Documentation
Breaking Changes