Add MarkdownEmbedPreview component + preview pane (CS-11673, CS-11674)#5303
Add MarkdownEmbedPreview component + preview pane (CS-11673, CS-11674)#5303FadhlanR wants to merge 3 commits into
Conversation
Preview deploymentsHost Test Results 1 files 1 suites 2h 1m 19s ⏱️ Results for commit f6ac9e3. Realm Server Test Results 1 files ±0 1 suites ±0 12m 3s ⏱️ - 1m 2s Results for commit f6ac9e3. ± Comparison against earlier commit 6700fe0. |
Build the reusable markdown-embed preview and its right-hand preview pane, the companion the combined chooser modal will compose later. - MarkdownEmbedPreview: renders a resolved card/file in a given format/size via CardRenderer; fitted sizing reuses bfmBlockFormatAndSize so the preview footprint matches the live markdown renderer. @kind controls inline/block placement, not the render format. - Preview pane: format dropdown (Atom / Embedded / each Fitted variant / Custom), always-on W×H inputs for Fitted with smart bidirectional variant matching, Inline/Block toggle (Block disabled while Atom is selected), and a dynamic "Insert as ..." CTA that emits the serialized BFM via @onInsert. - runtime-common: add serializeBfmSizeSpec (inverse of parseBfmSizeSpec) and serializeBfmRef as the single source of truth for BFM directive syntax; base markdown-helpers delegate to it so file refs serialize too. - Freestyle demos for both components plus unit and integration tests. Combines CS-11674 (W×H inputs) into this branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ment decoupling - host-freestyle: provide CardContext so previewed cards/files actually render (CardRenderer consumes it; the freestyle route only had the Get* contexts). - Pane layout: move the format dropdown to the top; place the W×H inputs after the Inline/Block toggle in the footer. - MarkdownEmbedPreview: add opt-in @showSurroundingText that renders the embed inside skeleton document text (inline flows in the paragraph, block breaks to its own line); extract a shared Embed component so the bare and in-context paths don't duplicate the inline/block markup. - Decouple format from placement: every format is selectable in both inline and block, and the preview tracks the true format × placement. The pane declares intent (kind + size) uniformly to serializeBfmRef; whether inline carries the size is owned by BFM's serializer and handled in CS-11704. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ae62c77 to
6700fe0
Compare
The provided CardContext assigned the raw card-resource `getCard`, which isn't assignable to CardContext.getCard's `getCard<CardDef>` type — ember-tsc flagged TS2322. Cast through `GetCardType` and reference `this.getCard` in the context, mirroring how `templates/index.gts` provides it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f6ac9e3e88
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| case 'atom': | ||
| return 'atom'; |
There was a problem hiding this comment.
Don’t emit unsupported block atom directives
When the default Atom option is switched to Block, this returns atom as the size specifier, so the CTA emits ::card[url | atom]. I checked the current BFM reader path: parseBfmSizeSpec does not accept atom, and block rendering falls back to embedded when no recognized data-boxel-bfm-format is produced, so users who insert from this state see an embedded card despite the preview/CTA saying Atom. Until the grammar/renderer supports block atom, this state should either serialize to a supported directive or be disabled.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds a reusable markdown-embed preview component and a companion right-hand preview pane for configuring BFM card/file embed directives, plus shared BFM serialization helpers so host + base realm emit consistent directive syntax.
Changes:
- Introduces
MarkdownEmbedPreview(pure render) andMarkdownEmbedPreviewPane(format/placement/size controls + “Insert as …” emitting serialized BFM). - Centralizes BFM directive serialization in
runtime-common(serializeBfmSizeSpec,serializeBfmRef) and updates base-realm markdown helpers to delegate to it. - Adds Freestyle demos and new unit/integration tests for BFM serialization + preview/pane behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/runtime-common/bfm-card-references.ts | Adds BFM size + reference serializers to centralize directive output. |
| packages/host/tests/unit/bfm-card-references-test.ts | Adds unit coverage for new serializer helpers. |
| packages/host/tests/integration/components/markdown-embed-preview-test.gts | Adds integration coverage for preview rendering across formats/placement. |
| packages/host/tests/integration/components/markdown-embed-preview-pane-test.gts | Adds integration coverage for pane controls and emitted BFM strings. |
| packages/host/app/templates/host-freestyle.gts | Provides full CardContext so Freestyle demos can render via CardRenderer. |
| packages/host/app/components/markdown-embed-chooser/preview/usage.gts | Freestyle usage/demo for MarkdownEmbedPreview. |
| packages/host/app/components/markdown-embed-chooser/preview/index.gts | New preview component implementation (format + placement + optional fitted sizing). |
| packages/host/app/components/markdown-embed-chooser/pane.gts | New preview-pane component (dropdown, toggle, W×H inputs, emits serialized BFM). |
| packages/host/app/components/markdown-embed-chooser/pane-usage.gts | Freestyle usage/demo for MarkdownEmbedPreviewPane. |
| packages/base/markdown-helpers.ts | Delegates embed directive construction to serializeBfmRef for consistent syntax. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private get sizeSpecifier(): string | undefined { | ||
| switch (this.category) { | ||
| case 'atom': | ||
| return 'atom'; | ||
| case 'embedded': | ||
| return 'embedded'; |
| matching), an Inline/Block toggle (Block is disabled while Atom is | ||
| selected, since atom has no block form), and a dynamic "Insert as …" | ||
| CTA. The CTA fires |
Summary
Builds the reusable markdown-embed preview and its right-hand preview pane — the companion the combined chooser modal (CS-11675) will compose later. Per discussion, CS-11674 (always-on W×H inputs with smart variant matching) is combined into this branch.
Cards/files embed in markdown via BFM directives (
:card[URL]inline /::card[URL | size]block). This lets a user pick a target, choose how it renders, toggle inline vs block, and get the correctly-serialized BFM.What's here
MarkdownEmbedPreview(markdown-embed-chooser/preview/index.gts) — pure render component. Given a resolvedCardDef/FileDef, a@format, and (for fitted) a@sizeSpec, it renders viaCardRenderer. Fitted sizing reusesbfmBlockFormatAndSize, so the preview footprint matches the live markdown renderer byte-for-byte.@kindcontrols inline/block placement, not the render format. With@showSurroundingTextit renders the embed inside skeleton document text so you can see how it sits in a real doc — an inline embed flows within the paragraph, a block embed breaks to its own line. A shared innerEmbedcomponent keeps the bare and in-context paths from duplicating the inline/block markup.MarkdownEmbedPreviewPane(markdown-embed-chooser/pane.gts) — format dropdown at the top (Atom / Embedded / each Fitted variant / Custom), a live preview, and a footer with the Inline/Block toggle, the W×H inputs (for Fitted/Custom, placed right after the toggle), and a dynamic "Insert as …" CTA that fires@onInsert(bfm). Format and placement are independent — every format is selectable in both inline and block, and the preview tracks the true format × placement.runtime-common/bfm-card-references.ts—serializeBfmSizeSpec(inverse ofparseBfmSizeSpec) andserializeBfmRef, the single source of truth for BFM directive syntax.base/markdown-helpers.tsdelegates to it so file refs (:file[…]) serialize too. The pane declares its intent uniformly ({ kind, size }) and lets this serializer decide what each placement carries.templates/host-freestyle.gts— provides the fullCardContextso the Freestyle preview usages actually render cards/files (CardRendererconsumes it via@consume).MarkdownEmbedChooser::Preview/::Pane), plus unit + integration tests.Serialization
Today
serializeBfmRefdrops the size for inline (inline is atom-only in the current BFM grammar)::card[URL]::card[URL | atom]:card[URL]::card[URL | embedded]:card[URL]::card[URL | tall-tile]:card[URL]::card[URL | w:300 h:200]Files use the
filekeyword. The preview already shows the selected format in both placements; the inline column collapses to a size-less:card[URL]only because BFM's serializer/grammar doesn't yet carry a spec for inline.Follow-up: CS-11704
Making inline carry a format/size is a BFM-grammar change tracked in CS-11704 ("BFM: support all formats in both inline and block reference directives"). When it lands, the inline column above becomes
:card[URL | <spec>]with no change to this chooser — it already passes the size throughserializeBfmRef.Notes for reviewers
@onInsert; cursor insertion is a later ticket.rendered-markdown) instead ofFittedCardContainer, because it covers custom W×H +%widths uniformly and guarantees parity with the live renderer.eslint,ember-template-lint, andember-tscare clean for the touched files; themarkdown-embedintegration suite passes locally against the dev stack (14 tests, 37 assertions).Screen Recording
Screen.Recording.2026-06-23.at.19.15.11.mov
🤖 Generated with Claude Code