Review findings on the Report an Issue modal:
1. Revert the description textarea from onInput back to onChange. The
onInput swap sidestepped a real React value-tracker dedup gotcha (a
test harness's raw `el.value = x` assignment looks like a no-op change
to a controlled onChange input), but this codebase already has the
correct fix for exactly that gotcha: bypass the tracker's patched
setter via the native prototype descriptor, as HeadCodeModal.test.tsx,
SiteDesignPanel.reset.test.tsx, shared-controls.test.tsx, and both
MediaStylePanel.*.test.tsx already do. Rewrote typeDescription() in
ReportIssueModal.test.tsx to use that idiom instead of bending the
component to fit the test.
2. The include-contents opt-out copy said unchecking it still sends "your
description, the page name and your browser details" but omitted
console errors, which buildReportPayload always includes regardless of
the checkbox and which can incidentally echo page content. Copy now
lists console errors explicitly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Wires the Task 18 payload builder and Task 16/17 diagnostics into a
user-facing modal, reachable from the topbar bug icon (desktop) and
overflow menu (mobile). Two gaps in the task brief's draft, not called
out there, are handled explicitly: buildReportPayload() can throw when
the payload is still oversized after canvas_state is dropped, so
submission is wrapped in try/catch with an actionable "too large" error
that preserves the user's typed text; and the textarea maxLength is
sourced from MAX_DESCRIPTION_CHARS (with a proximity character count)
instead of a hardcoded number, so the UI limit can't drift from the
payload limit.
Also portals the modal to document.body for the same stacking-context
reasons TemplateModal/HeadCodeModal already do, and guards the
useEditor() selection collector with optional chaining so it degrades
gracefully under TopBar's existing test harness (a minimal @craftjs/core
stub with no events/nodes on its collector state).
The textarea uses onInput rather than onChange: React's onChange dedup
(via its DOM value-tracker) treats a test harness's raw `el.value = x`
assignment as a no-op change, matching this repo's existing pattern
(HeadCodeModal.test.tsx, shared-controls.test.tsx, etc. all work around
the same gotcha) -- onInput is a plain passthrough with no such check,
and is behaviorally identical for real typing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>