Collapse encoded media in editable fields too - #534
Merged
Conversation
Base64 in a request body is never typed by hand. It arrives pasted, and the only edit anyone makes is replacing it wholesale, which atomic ranges already give us. So a tag stands in for it without hiding anything anyone meant to read, and you see `PNG · 2.7 KB` with a thumbnail where you pasted. Only the media rule crosses over. The two that hide text by length alone stay read-only: under the column rule a minified body would become uneditable past the limit, which really would be editing text you can't see. Finding the media had to change to make this work at all. Every editable field mixes its language with the twig parser, which mounts the base language as an overlay, and overlays are not traversed by `Tree.iterate` — a rule that walks the tree sees one enormous Text node and finds nothing inside it. So the media rule now reads the text for a run of base64 instead, which no grammar can describe better than the alphabet does, and which works the same in every language. A `data:` header is picked up by looking back from the run. Read-only output is unchanged, verified value by value against a response holding one of every supported type.
Greptile SummaryThe PR collapses recognizable encoded media in editable CodeMirror fields while retaining the broader length-based collapsing rules only for read-only output.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/yaak-client/components/core/Editor/largeValues.ts | Splits media detection from grammar-based length rules, introduces editable media decorations, and updates widget context-menu behavior. |
| apps/yaak-client/components/core/Editor/Editor.tsx | Configures editable editors with the new media-only extension while preserving the full rule set for read-only editors. |
| apps/yaak-client/components/core/Editor/extensions.ts | Defines separate read-only and editable extension bundles for large-value collapsing. |
| apps/yaak-client/components/core/Editor/largeValues.test.ts | Adds coverage for editable media, data URIs, template overlays, range boundaries, and preservation of length-only content. |
| apps/yaak-client/lib/contextMenu.ts | Adds trigger-element ownership and menu toggle semantics to global context-menu state. |
| apps/yaak-client/components/core/Dropdown.tsx | Generalizes menu trigger refs to arbitrary HTML elements and passes them into outside-click handling. |
| apps/yaak-client/lib/largeValue.ts | Separates image clipboard copying from encoded-text copying while preserving fallback behavior. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Editor document and visible ranges] --> B{Read-only?}
B -->|Yes| C[Apply media, large-token, and column-cut rules]
B -->|No| D[Apply media rule only]
C --> E[Create replacement decorations]
D --> E
E --> F[Render atomic media tag]
F --> G[Toggle context menu]
G --> H[Copy image or encoded text]
G --> I[Preview or save media]
Reviews (4): Last reviewed commit: "Drop the repeated icon on the paired cop..." | Re-trigger Greptile
Clicking the tag while its menu was open did nothing visible. The menu's outside-click handler runs on mousedown in the capture phase, so it closed the menu before the tag's own click handler ran and reopened it. `Menu` already solves this for a normal dropdown: it takes a `triggerRef` and excludes it from what counts as outside. `ContextMenu` just never passed one, because it was written for menus opened at a cursor, which have no trigger element. It can now be given one, and opening became a toggle, matching `toggleDialog`.
greptile-apps
Bot
dismissed
their stale review
August 13, 2026 19:33
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Copying a picture put the picture on the clipboard, which is what you want for pasting it somewhere, and nothing for pasting it back into a request. Both are now offered, so the one action no longer has to guess which was meant. The text entry says Base64 when we know that is what it is, since that explains what you are about to get better than "Copy" does.
greptile-apps
Bot
dismissed
their stale review
August 13, 2026 19:46
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Two copy entries in a row with the same icon read as two unrelated things. Leaving the second blank keeps the indent, so the pair reads as one action with a choice of what to take.
greptile-apps
Bot
dismissed
their stale review
August 13, 2026 19:53
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Base64 in a request body is never typed by hand. It arrives pasted, and the only
edit anyone makes is replacing it wholesale, which atomic ranges already give us.
So a tag can stand in for it without hiding anything anyone meant to read, and
you see
PNG · 2.7 KBwith a thumbnail where you pasted.Only the media rule crosses over. The two that hide text by length alone stay
read-only, since under the column rule a minified body would become uneditable
past the limit.
Finding the media had to change to make this work at all. Every editable field
mixes its language with the twig parser, which mounts the base language as an
overlay, and overlays are not traversed by
Tree.iterate, so a rule that walksthe tree sees one enormous Text node and finds nothing inside it. The media rule
now reads the text for a run of base64 instead, which works the same in every
language. Read-only output is unchanged, checked value by value against a
response holding one of every supported type.