Skip to content

Add emoji interpolation to markdown blocks#74

Merged
StephenTangCook merged 3 commits into
mainfrom
claude/pensive-goldberg-DV4yC
Jun 10, 2026
Merged

Add emoji interpolation to markdown blocks#74
StephenTangCook merged 3 commits into
mainfrom
claude/pensive-goldberg-DV4yC

Conversation

@StephenTangCook

Copy link
Copy Markdown
Collaborator

Summary

The markdown block now interpolates Slack emoji shortcodes (:shortcode:), bringing it to feature parity with other block types that use the mrkdwn parser. Previously, emoji shortcodes rendered as literal text in markdown blocks because react-markdown + remark-gfm had no emoji rule.

Key Changes

  • New remark plugin (src/utils/remark_slack_emoji.ts): A lightweight mdast plugin that splits text nodes on :shortcode: patterns and emits placeholder elements, while preserving emoji inside code spans and fenced code blocks
  • Updated markdown block (src/components/blocks/markdown_block.tsx): Integrated the new plugin into the remark pipeline and mapped the placeholder elements to the existing <SlackEmoji> component, ensuring custom emoji (hooks.emoji), standard emoji, aliases, and skin tones all behave identically across block types
  • Comprehensive test suite (test/markdown_emoji.test.mjs): Node.js tests covering standard shortcodes, aliases, skin-tone modifiers, custom emoji via hooks, and code span/block preservation
  • Playground fixture (playground/src/fixtures.ts): Added a demo showcasing emoji rendering in markdown blocks alongside code examples
  • CI integration (.github/workflows/main.yml, package.json): Added test execution to the build pipeline

Implementation Details

  • The emoji regex mirrors the mrkdwn parser's slack_emoji tokenizer to ensure consistent shortcode matching
  • Code nodes (code and inlineCode) are never split, preserving Slack's behavior of not interpolating emoji in code
  • The plugin reuses the existing <SlackEmoji> component rather than duplicating emoji logic, eliminating divergent behavior between block types
  • Minimal mdast typings are defined locally to avoid adding @types/mdast as a dependency

https://claude.ai/code/session_01Qea1JoBqVXi6R8Fw3QWCr7

claude added 3 commits June 7, 2026 03:08
The `markdown` block renders through react-markdown + remark-gfm, which
had no emoji rule, so `:shortcode:` (custom and standard) rendered as
literal `:name:` text — unlike every other block type, which goes through
the mrkdwn parser's slack_emoji rule.

Add a `remarkSlackEmoji` plugin that splits mdast text nodes on
`:shortcode:` (skipping inline and fenced code) and renders them through
the same <SlackEmoji> component the mrkdwn parser uses, so custom emoji
(hooks.emoji), standard emoji, aliases and skin tones all behave
identically across block types.

Tests cover the new behavior via Node's built-in test runner (no new
deps) against the built package.

https://claude.ai/code/session_01Qea1JoBqVXi6R8Fw3QWCr7
Reframe the playground fixture as a standard deploy-summary message
instead of a "now emoji work" demo, while still exercising emoji in a
header, prose, list items, a skin tone and an alias.

https://claude.ai/code/session_01Qea1JoBqVXi6R8Fw3QWCr7
Trim the plugin and test file headers and the MarkdownEmoji comment to
five lines or fewer.

https://claude.ai/code/session_01Qea1JoBqVXi6R8Fw3QWCr7
@StephenTangCook StephenTangCook force-pushed the claude/pensive-goldberg-DV4yC branch from eaf991e to 4dadd71 Compare June 7, 2026 03:10
@pkg-pr-new

pkg-pr-new Bot commented Jun 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/slack-blocks-to-jsx@74

commit: 4dadd71

@themashcodee

Copy link
Copy Markdown
Owner

Thanks for this @StephenTangCook — really clean contribution. I built the branch locally and rendered it through ReactDOMServer, and the behaviour all checks out: emoji shortcodes interpolate in markdown blocks now, and crucially the output matches the section/mrkdwn path for the same text, which is exactly the parity goal. Nice work reusing instead of duplicating the emoji logic, and the recursion into child nodes means it works in headings, bold, lists, blockquotes, and link text too. Code spans and fenced blocks correctly stay literal, and the hooks.emoji path fires as expected. Your 7 tests pass.

Here are the blocks I used to verify, in case they’re useful:

[
  { "type": "markdown", "text": "## :rocket: Heading\n\n**bold :fire:** and a [link :star:](https://example.com)\n\n- list item :zap:\n\n> quote :bulb:" },
  { "type": "markdown", "text": "inline `:rocket:` stays literal\n\n```\n:rocket: stays literal\n```" },
  { "type": "markdown", "text": "ship it :tada: nice :smile:" },
  { "type": "section", "text": { "type": "mrkdwn", "text": "ship it :tada: nice :smile:" } }
]

Overall this is solid — happy to see it land. 👍

@StephenTangCook StephenTangCook merged commit bb2b269 into main Jun 10, 2026
5 checks passed
@StephenTangCook StephenTangCook deleted the claude/pensive-goldberg-DV4yC branch June 10, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants