feat(stepper): render inline thumbnails for opaque values (DrRacket style) - #90
Conversation
…tyle) Adds an `image` SyntaxTemplatePart (renders a node's data-URL property as an inline <img>, falling back to nothing when absent, like `child`/`list`) and an `unless` part (the inverse of `when`, for pairing an image with a textual fallback) to common-stepper. web-stepper renders both generically. A language opts in by using them in its SyntaxProfile templates — see the companion py-slang PR, which wires this up for opaque module values (e.g. a `rune` Rune) that attach a stepper-thumbnail render hook. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193EaXSjQ3fGYJGCU1uDvmD
🦋 Changeset detectedLatest commit: cab24aa The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR 💥 An error occurred when fetching the changed packages and changesets in this PR |
|
@codearabbitai review |
ReviewSmall, well-scoped PR that extends the stepper's declarative template language with Three things worth addressing:
Also confirmed the |
- Fix `unless` doc comment, which referenced `node[when]` instead of `node[unless]`. - Enforce that the `image` part's src is actually a `data:` URL before rendering it, instead of trusting any string — a live network URL there would let a render silently leak the viewer's IP/referrer to a third-party host. - Drop the no-op `@sourceacademy/web-stepper` patch bump from the changeset: that package is in .changeset/config.json's `ignore` list (bundled host plugin, not independently published), matching how prior stepper-only changes (e.g. #49) only bumped common-stepper. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017rkUEePRmhJmjB3whkhU6s
Summary
common-stepper: adds animageSyntaxTemplatePart(renders a node's data-URL property as an inline<img>, falling back to nothing when absent, likechild/list) and anunlesspart (the inverse ofwhen, for pairing an image with a textual fallback).web-stepper: renders both generically inSubstVisualizer.tsx, plus CSS (.stepper-opaque-thumbnail) sizing the image to text height, DrRacket-style, rather than expanding the line.A language opts in by using these in its
SyntaxProfiletemplates — companion change: source-academy/py-slang#402, which wires this up for opaque module values (e.g. aruneRune) that attach a stepper-thumbnail render hook (see source-academy/modules's opaque-thumbnails doc).Verified live end-to-end against a local build of this branch + the py-slang PR + the already-shipped
runethumbnail hook:from rune import red, heart; red(heart)renders the plainheartthumbnail inline as the argument, and the red-colored result's own thumbnail after stepping through the call.Test plan
yarn workspace @sourceacademy/common-stepper build— clean (pre-existing vitest/jest config warning unrelated to this change)yarn workspace @sourceacademy/web-stepper build— clean (pre-existingcommon-tabs/renderFunctionArgumentswarnings unrelated to this change)yarn eslint --concurrency=auto src/common/stepper/src/index.ts src/web/stepper/src/SubstVisualizer.tsx src/web/stepper/src/styles.ts— cleansourceacademy.orgplayground, Python §2 Stepper,from rune import red, heart\nred(heart)— thumbnail renders inline at each relevant step🤖 Generated with Claude Code
https://claude.ai/code/session_0193EaXSjQ3fGYJGCU1uDvmD