feat: media-image rich-editor extension - #12
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds MediaImageNode (name mediaImage) and MediaImageView, the React NodeView rendering the ephemeral url/mediaAlt attrs with an alt-text input and a conversion select. Task 7 will add the toolbar and registerMediaImage() to the same file. Installs @testing-library/user-event for the NodeView interaction tests.
Adds the editor toolbar button that opens the LibraryView in pick mode and inserts mediaImage nodes on confirm, wires registerMediaImage() into plugin.ts so the extension is registered eagerly before the editor mounts, and adds the EditorExtensionProps["media-image"] type augmentation plus matching en/de translations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wires the RichEditor's body field with the MediaImage extension into
the workbench ProductMediaForm/Page, persisting the document and
syncing referenced media into the "content" collection, and adds a
browser test asserting the stored node has only {id, alt, conversion}
and the value round-trips on reload.
…d errors Validates isImage() alongside the attach gate, constrains the picker's upload accept to image/*, and replaces the generic reused validation message with an id-carrying editor.not-attachable key so failures (missing, gate-denied, non-image) are diagnosable. Adds Feature coverage for the new non-image rejection, a nested mediaImage node, and sanitizer-preserved width/height/loading attrs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The insert-image toolbar control statically imported Dialog and LibraryView, dragging the whole media-library grid stack into the eager extension bundle registered at plugin boot. Extracts the dialog body into media-image-dialog.tsx and loads it with React.lazy + Suspense, only when the dialog is open. Test ids and insert attrs are unchanged; a standalone media-image-dialog chunk now shows up separately in the build output. Also asserts the "Original" conversion option renders alongside the configured conversions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Adds a
media-imagerich-editor extension built on lattice's server-side extension API: pick images from the media library insideRichEditor, store only{id, alt, conversion}per node, and resolve URLs server-side on every render/prefill (temporary/signed disk URLs just work).MediaImage(#[AsEditorExtension('media-image')], registered app-wide) +MediaImageNode(tiptap-php).prepareDocument()batch-resolves ids into ephemeralurl/width/height/mediaAltattrs that are scrubbed before storage;validateDocument()rejects missing, gate-denied, and non-image media with per-id messages; the sanitizer allows exactly whatrenderHTML()emits.LibraryViewdialog (carried in the extension's wire props). The dialog is lazy-loaded so the media grid stays out of the eager bundle.MediaImage::idsIn($document)feeds the existingsyncMedia()— documented in the README together with themediaConversions()pairing.Usage:
Testing
composer checkgreen on lattice 0.36.0: Pint, Larastan, 143 Feature tests (409 assertions) — extension seams (wire shape, ephemeral scrub, batch URL resolution incl. conversions + nested nodes, sanitizer attrs, validation modes,idsIn).npm run test(39) +npm run typecheck+npm run buildgreen.url), attachment row in thecontentcollection → reload re-renders the image.🤖 Generated with Claude Code