Commit graph

12 commits

Author SHA1 Message Date
mwiegand
10cf0da3d2
fix(editor): capture-phase keydown + popup leak + cache warmup
Addresses Critical #1 + Important #2/#3/#4 from the Task 9 code review.

CRITICAL — Tab/Enter were stolen by CodeJar before the popup handler
saw them. CodeJar registers its keydown listener during construction
(line ~159), so it ran first in bubble order: Tab handler
preventDefaulted and inserted 2 spaces, Enter handler preventDefaulted
+ stopPropagation'd (with leading indent), so the popup-accept either
ran on corrupted state or never fired at all. Fix: register the popup
listener with {capture: true} and call stopPropagation on the keys we
own — that way capture phase fires before CodeJar's bubble listener
and the key is fully consumed by the popup while it's visible. Normal
typing (popup hidden) early-returns without stopPropagation, so
CodeJar's tab-indent + enter-preserve-indent still work when there's
no autocomplete to accept.

IMPORTANT — destroy() leaked the popup <ul> into document.body. Each
mount/destroy cycle (e.g. modal close/reopen) left an orphan popup.
Fix: pop.remove() in destroy().

IMPORTANT — async refreshPopup could race in stale renders if the
first keystroke fired the vocab fetch and the second keystroke
captured a different ctx before the fetch resolved. Fix: warm the
cache with a fire-and-forget loadVocab(language) at mount, so the
first user keystroke hits cache. Eliminates the only realistic window
for the race.

IMPORTANT — acceptCompletion's Range.setStart could throw
IndexSizeError on pathological state (caret inside a tokenized span
where the fragment isn't fully upstream). Fix: try/catch the entire
DOM mutation block, log + dismiss on failure. Plus an inline comment
documenting the single-text-node invariant the current grammars hold.

Plan source updated for the capture-phase fix (most important for
future regeneration); the other fixes are smaller and only mirrored
into the actual code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 20:49:23 +02:00
mwiegand
4bace3ab5a
plan(textarea-editor): fix stale jar reference in autocomplete
The Task 9 plan template used the captured \`jar\` closure variable in
acceptCompletion, which becomes stale after setLanguage's
tear-down-and-remount. Same class of bug Task 4's review caught and
fixed. Update the plan to match the correct implementation.
2026-05-16 20:42:16 +02:00
mwiegand
c6f10e632d
test(blueprint): also assert prism.css is referenced in editor assets
The plan template (and verbatim implementation) listed five of the six
editor asset URLs in the structural test — vendor/prism.css was
omitted. If a future change drops the Prism stylesheet from the
partial, syntax tokens lose their color rules silently and the test
still passes. Add the missing assertion and update the plan to match.

Addresses Minor #1 from the Task 6 code review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 20:35:44 +02:00
mwiegand
04f9a4d6a2
fix(editor): narrow findFilenameInput scope + dispatch input from setValue
Addresses two Minor follow-ups from the Task 4 code review:

- findFilenameInput previously included `body` in its closest() selector,
  meaning any "auto" textarea outside a modal would walk all the way up
  and pick up the files-editor modal's filename input from elsewhere in
  the document. Drop `body` so out-of-modal "auto" usage degrades
  cleanly to "plain".
- setValue now dispatches an `input` event on the textarea after
  writing, matching the onUpdate mirror. Task 10 wires the files-editor
  modal to call setValue when loading file content — without this fix,
  textarea-listening code (e.g. unsaved-changes indicators) wouldn't
  see programmatic loads. Now setValue and user typing produce the
  same observable side effects.

Plan source block updated to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:35:47 +02:00
mwiegand
e058b45ff2
plan(textarea-editor): consolidate Task 4 editor.js into one block
The plan had Step 1 (initial widget) + Step 2 (setLanguage patch); the
implementation merges them into one final file. Update the plan to
show the final file verbatim so a future regeneration produces the
same output. Step 2 in the plan is renumbered to 'Manual verification
note' (just the deferred-to-Task-6 sentence) for completeness.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:30:22 +02:00
mwiegand
cdcb7e4853
style(editor): visible light-mode popup active state + plan sync
Addresses Important #1 + Minor #2/#3 from the Task 3 re-review:

- --color-bg-popover-active light value: #f3f4f6 → #e5e7eb. The prior
  value was within ~1.05:1 luminance of the white surface — keyboard
  navigation through the autocomplete list had no visible focus
  indicator in light mode. e5e7eb (Tailwind gray-200) clears that.
- Drop dead fallback hexes on the four guaranteed tokens
  (--color-string/-keyword/-number/-bg-popover-active). They never
  fired post-fix and only produced a dark-mode-only palette if
  tokens.css somehow failed to load — i.e. they were misleading.
- Plan source block (Task 3 Step 2) replaced with the post-fix CSS
  verbatim + a new Step 2b that documents the tokens.css additions
  alongside the editor.css template, so a fresh regeneration
  produces the same file.

Deferred: cross-cutting --font-mono token (Minor #4 — would touch 7+
sites outside Task 3's scope).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:27:07 +02:00
mwiegand
f9c8518212
style(editor): theme-aware syntax tokens + match textarea metrics
Addresses Important #1 + #2 from the Task 3 code review:

- Adds --color-string, --color-keyword, --color-number,
  --color-bg-popover-active to tokens.css in both the :root and dark
  blocks. GitHub-style palette tuned for legibility on each theme's
  surface.
- Updates .editor-code to use the same padding tokens, font-family
  stack, font-size, and line-height as the existing textarea rule so
  the contenteditable doesn't visibly jump when the widget mounts.
- Drops the caret-color override (browser default adapts to system
  theme — no token needed).

Plan source block updated to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:22:27 +02:00
mwiegand
db1a255223
fix(editor): drop dead -? from srccfg number regex
The `\b` word boundary anchor prevents the optional minus from ever
matching from positions where signed numbers naturally appear (` -1`,
`(-1`, `=-1` all word-boundary-from-non-word and the `-?` fires zero
chars). Negative numbers are tokenised via the operator class instead,
which is the consistent behaviour the grammar already exhibits.
Plan source block updated to match so a fresh regeneration produces the
same file.

Addresses Minor #1 from the Task 2 code review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:15:34 +02:00
mwiegand
4a1b6d5fac
plan(textarea-editor): make Prism bash-grammar grep minifier-safe
Spec reviewer caught that the literal 'Prism.languages.bash' string
doesn't appear in the minified prism.js (minifier renames Prism→e).
Switch the verification grep to match either the bash shebang token
or any languages.bash assignment; both survive minification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:10:56 +02:00
mwiegand
f5ac61d99b
plan(textarea-editor): fix CodeJar download URL (v4.x at dist/codejar.js)
Task 1 implementation discovered that codejar v4.0.0 ships its
browser bundle at /dist/codejar.js, not the package root. The vendor
README already records the correct URL; this patch keeps the plan
itself accurate for future regeneration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:05:23 +02:00
mwiegand
1ec5e80a73
plan(textarea-editor): use curl-based vendoring (subagent-executable)
The original Task 1 instructed a human to click through prismjs.com's
configurator UI — a step a subagent can't perform. Replace with direct
curl from jsdelivr for both Prism components (core + clike + bash
concatenated) and CodeJar, plus a sed-based ESM-export strip and a
window-global shim. Updates the vendor README template accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 19:00:48 +02:00
mwiegand
9618109f0f
plan(textarea-editor): 12-task TDD implementation plan
Vendors Prism + CodeJar, builds the editor widget incrementally
(mount/sync → highlighting → autocomplete → files-editor integration),
scaffolds Playwright + writes the e2e editor test. Form-contract Python
tests guard each call-site wiring step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 18:04:56 +02:00