Repository navigation
Conversation
Markup had no way to represent an animated GIF. Images exist, but the image node is disabled in both message composers via kitOptions, so a GIF sent in chat had nowhere to live. This adds a first-class `gif` node rather than re-enabling images, which keeps the composers' existing image policy untouched. What changed: - `MarkupNodeType.gif` plus a GifNode tiptap extension, registered in the server kit as well as the client so stored markup round-trips. - Markdown and HTML serialization both ways. The HTML case reads `src` OR a blob reference; an earlier draft read only `src` and silently produced `src="undefined"` for blob-backed GIFs. - `insertGif` on the editor handler, implemented across every editor that exposes one so no composer is silently missing it. - The node enabled in both message composers. - Rendering in BOTH markup viewers. `NodeContent.svelte` had a branch for image and none for gif, so a GIF rendered as the literal text `unknown node: "gif"`; `LiteNodeContent.svelte` rendered nothing at all. Two things worth calling out for reviewers: `gif` is added to `nonEmptyNodes` in text-core. Without it a message containing only a GIF counts as empty, so `canSubmit` stays false and the send button never enables. `emoji` is already on that list for the same reason. This is easy to miss because serialization tests all pass while the feature is unusable. `markupViewerCoverage.test.ts` is a structural test: it reads the viewer sources and asserts each composable node type has a branch. It exists because the missing-branch bug above passed every serialization test in the suite. `packages/presentation` had jest and node types but no test script, so this adds `test` and `_phase:test` to run it in CI. Signed-off-by: Shannon Kerr <shannon@exaviz.com>
8f2737e to
90b8bbe
Compare
|
Rebased onto current Checked locally with the build cache off: This is part 1 of a GIF picker for the message composers: it only adds the |
|
Hi @shanzez
With alt='Cat says "hi"', markdown-it no longer recognises the tag as html_inline. The whole <img data-type="gif" …> becomes a plain text token, so the GIF disappears and the reader sees raw HTML. Titles from GIF providers often contain quotes. Fix: use state.htmlEsc(...) for every attribute in that case (it already exists in the same file). Also add tests with a " and a * in the alt text. The existing image fallback path at around line 207 has the same bug, but it rarely runs.
Full editor (image enabled): This affects every path that goes HTML → ProseMirror with the default kit. That includes htmlToJSON/htmlToMarkup in text/markup/utils.ts (which the api-client markup client and the importers use), and copy/paste inside a document editor. A GIF copied out of a doc and pasted into chat arrives as an image node, which the composer then drops. The PR’s HTML tests only cover the separate text-html parser, where the data-type check works, so this gap isn’t covered. Fix: add priority: 60 to the gif parse rule, or register gif before image in both kits. Add a test that runs jsonToHTML → htmlToJSON through the server kit with image enabled.
|
- Markdown: escape the raw <img> attributes with htmlEsc. The markdown escaper left " intact, so a quoted alt broke the tag into text, and its backslashes piled up in the alt on every save. The sized image fallback had the same bug and gets the same fix. - Parse priority 60 on the gif rule, so ImageNode's img[src] rule cannot claim a gif in kits where image is enabled (ServerKit, StaticEditorKit via GifExtension). - markupToHtml emits file-id alone for a library gif. A bare blob id is not a resolvable src, and it came back as a bogus src on parse. - Tests for each: quoted and punctuated alt round trips (gif and sized image), a ServerKit jsonToHTML -> htmlToJSON round trip in its own file because utils.test.ts mocks @tiptap/html, and no src for a library gif. Each new test fails without its fix. Signed-off-by: Shannon Kerr <shannon@exaviz.com>
|
@ArtyomSavchenko thanks for the careful review, all four reproduced. Fixed in d40aca2:
Locally with the build cache off: |
Summary
Markup has no way to represent an animated GIF. Images exist, but the image node is disabled in both message composers via
kitOptions(AttachmentRefInput.svelteand communication'sTextInput.svelte), so a GIF sent in chat has nowhere to live.This adds a first-class
gifnode rather than re-enabling images, which leaves the composers' existing image policy untouched.It is deliberately source-agnostic: the node accepts either a blob reference or an external
src, so a workspace-hosted GIF and a third-party one both work. No provider is included here.What changed
MarkupNodeType.gifintext-core, plus aGifNodetiptap extension registered in the server kit as well as the client, so stored markup round-trips through the server.srcor a blob reference — an earlier draft read onlyattrs.srcand silently emittedsrc="undefined"for blob-backed GIFs.insertGifonTextEditorHandler, implemented in every editor that exposes one. There are five call sites, not four:TextEditor.svelteholds the low-level export the others delegate to.defaultRefActionsand communication'sdefaultMessageInputActions) fanning out to ~10 surfaces, so a blanket swap would have changed editors that should not gain the action.NodeContent.sveltehad a branch for image and none for gif, so a GIF rendered as the literal textunknown node: "gif".LiteNodeContent.svelterendered nothing at all.Two things worth a reviewer's attention
gifis added tononEmptyNodes. Without it, a message containing only a GIF counts as empty, socanSubmitstays false and the send button never enables — the feature looks broken in exactly the case people use it for.emojiis already on that list for the same reason. This is easy to miss because every serialization test passes while the feature is unusable.markupViewerCoverage.test.tsis a structural test. It reads the viewer sources and asserts that each composable node type has a branch, because the missing-branch bug above passed the entire serialization suite. Reading files needs node types, hence thetypesaddition topackages/presentation's tsconfig. If you would rather not have a source-reading test, say so and I will drop it — but something needs to catch that class of bug.Verification
Built and exercised on a self-hosted instance running this node in production chat, including the GIF-only message case.
rush validateandrush svelte-checkpass on the branch this was developed on. This PR is a clean cherry-pick ontodevelop; CI here is the first run against this base.