Tags: microsoft/SwiftStreamingMarkdown
Tags
Fix paragraph/heading width hugging; add LLM Chat sample demo (#162) * Fix paragraph/heading width hugging; add LLM Chat sample demo Remove the `HStack { ParagraphView(); Spacer() }` wrapper from the .paragraph and .heading cases in SingleBlockView. The unqualified Spacer() forced blocks to report the full offered width upward, breaking ancestors that hug content to the text's natural width (e.g. chat bubbles). ParagraphView already renders left-aligned and the outer VStack is `.leading`, so alignment is unchanged. Also align the snapshot CanvasView harness to `.leading` and re-record the affected iOS references. Add an interactive "LLM Chat" sample demo (LLMChatView + LLMChatViewModel + non-isolated LLMChatInteractor) showcasing role-aligned bubbles with progressively streamed rich Markdown. Fixes #157 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Backfill macOS snapshot references for width-hugging change Copy the 26 affected macOS-standard light/dark references (13 test methods) recorded by the Record macOS Snapshots workflow, matching the iOS references re-recorded after removing the paragraph/heading Spacer wrapper. Refs #157 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Cap LLM Chat width on macOS Constrain the conversation column and composer to a centered 640pt max width on macOS so the chat doesn't stretch across a wide window; iOS keeps full width. Refs #157 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Jun Yan <yanjun@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document image support; add Images demo and snapshot test (#146) * Document image support; add Images demo and snapshot test Finalize block-level image support (parts 1-4 already shipped) with the non-rendering deliverables: - README: move Images into the supported list with an accurate description of the experimental ImageConfig source types and fullscreen viewer. - Sample app: add an Images demonstration (enum case, subtitle, fixture) showcasing asset-catalog, bundled-resource, and remote sources, plus image-alongside-text splitting and an unresolved-source placeholder. - Tests: add ImageBlockSnapshotTests rendering a deterministic bundled image via Image(mdImage:); bundle test resources via Package.swift and record the iOS reference snapshots. Refs #89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Add MarkdownListener bundled-resource fallback; address review Addresses review comments on the image-support PR: - Add `MarkdownListener.resolveBundledResource(fileName:ext:)` (default returns nil). The renderer now resolves bundled-resource images from the app's main bundle first and falls back to the listener when absent, so consumers can serve images that live in a dependency package or framework bundle rather than the app target. Threaded through BundledResourceImage, the fullscreen viewer, and the image-tap payload. - README: move Images up under Paragraphs in the supported list. - Tests: parse Markdown containing a bundled image and verify end-to-end resolution via the listener (the resource lives only in the test bundle); cover the no-listener case; render the image deterministically via Image(mdImage:) for the visual snapshot. Replace the helper's fatalError with throwing XCTUnwrap so a missing resource is a normal test failure. Refs #89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Snapshot the image failure case; make image controller non-optional Addresses the second review round on PR #146: - Replace the bundled-image snapshot with the deterministic failure case: a remote image whose host is not in the allowed domains resolves to nil and renders BlockImageFailureView synchronously. The remote and bundled loading paths render asynchronously via `.task`, which the synchronous snapshot harness captures as the loading placeholder, so they can't be snapshotted deterministically. - Remove the direct Image(mdImage:) snapshot and the bundled-resource pipeline-logic tests from the snapshot file; move listener-fallback resolution coverage into ImageTapTests as a fast unit test. - Make ImageData.makeMarkdownImage(controller:) take a non-optional MarkdownController (the default only existed for test convenience); unwrap the environment controller in BlockImageView before building the payload. Refs #89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Add macOS snapshot references for the image failure test Recorded via the Record macOS Snapshots workflow (runs/29458940981) so the macOS SPM CI job has references for the new failure-placeholder snapshot. Refs #89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Surround snapshot image with text; keep image controller optional Addresses the latest review comments on PR #146: - Snapshot: the failure-placeholder test now parses a paragraph before and after the image, so the rendered DocumentView shows text/image/text. - Revert makeMarkdownImage(controller:) to an optional MarkdownController. SwiftUI's environment injection does not guarantee a non-nil controller, so BlockImageView optionally chains onImageTap rather than guarding out. Refs #89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Re-record macOS snapshot references for the text-wrapped image test Regenerated via the Record macOS Snapshots workflow (runs/29460803999) after surrounding the snapshot image with text. Refs #89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 --------- Co-authored-by: Jun Yan <yanjun@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix macOS crash when rendering markdown links (#130) * Fix macOS crash when rendering markdown links Link.convert stored an empty Swift array as the .underlineStyle attribute value: in a [NSAttributedString.Key: Any] context the [] literal infers as an empty array, not NSUnderlineStyle. TextKit expects an NSNumber there and AppKit calls -integerValue on it during layout, crashing NSTextView with -[Swift.__EmptyArrayStorage integerValue]. UIKit tolerates the bad value, which is why iOS never crashed. Store NSUnderlineStyle([]).rawValue instead and add a regression test asserting the attribute bridges to NSNumber. Fixes #128 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add attribute type-safety audit test Walks every attribute the conversion pipeline emits across paragraphs, lists, and tables (bold, strikethrough, links, inline code, LaTeX, citations, task lists) and asserts the value types TextKit expects: NSNumber for numeric keys, platform color/font for styling keys, URL, NSTextAttachment, and NSParagraphStyle. Fails on any platform when a wrongly-typed attribute enters the pipeline, so the crash class fixed in the previous commit cannot silently return through another key. Refs #128 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Update macOS snapshots from CI runner (macOS 26.4) (#116) Replace locally-recorded macOS snapshots with those generated on the CI runner to ensure pixel-perfect match during CI validation. Recorded via the Record macOS Snapshots workflow on macos-26 runner. Co-authored-by: Jun Yan <yanjun@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore sample streaming demo controls (#80) * Restore sample streaming demo controls Adds the sample app streaming drawer, playback speed controls, performance metrics, theme picker, and simulator destination selection improvements for local demo builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tighten drawer reveal scroll threshold Only auto-scroll completed content when revealing the controls drawer if the scroll view is effectively at the bottom, avoiding jumps after the user scrolls up slightly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update new sample file headers Matches the new SwiftLint file_header pattern from main for the sample streaming demo files added by this branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address streaming demo review feedback Derive the preferred simulator runtime from the active iPhoneSimulator SDK and preserve simulated stream delay while playback is paused. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Consolidate sample playback, metrics, and streamed source into DemonstrationViewModel - Merge StreamingPlaybackController + StreamingPerformanceModel + TextSimulatedStreamSource into a single @mainactor DemonstrationViewModel that conforms to StreamedMarkdownSource. - Switch scroll-bottom detection to iOS 18's .onScrollGeometryChange (drops the GeometryReader + PreferenceKey + coordinate-space plumbing). - Rewrite waitUntilPlaying() as an event-driven for-await over $isPlaying.values instead of a 75ms busy-poll. - Replace the fastForwardRequest version counter with a Bool flag (isFastForwarding) reset in the existing reset() chokepoint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Move drawer + scroll-bottom UI state onto DemonstrationViewModel Pull isAtScrollBottom and isControlDrawerPresented out of DemonstrationView's local @State and onto the shared viewmodel as @published properties. Drops the @binding chain that threaded isPresented through StreamingControlDrawerView and StreamingControlPanelView; both views now read/write viewModel.isControlDrawerPresented directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Mahyar (Mac) McDonald <252041286+mamcdonald_microsoft@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jun Yan <junyan.cpp@gmail.com>