Skip to content

Fix mailto: and tel: links in markdown content - #1153

Merged
mikebarkmin merged 7 commits into
mainfrom
claude/hyperbook-mailto-tel-links-5rdklw
Aug 7, 2026
Merged

Fix mailto: and tel: links in markdown content#1153
mikebarkmin merged 7 commits into
mainfrom
claude/hyperbook-mailto-tel-links-5rdklw

Conversation

@mikebarkmin

Copy link
Copy Markdown
Member

makeUrl only passed URLs through untouched when they contained "://" or
started with "data:". Every other scheme was treated as a relative path,
so a markdown link like Write us was joined with the base
path and rendered as href="/mailto:a@b.c". Links configured in
hyperbook.json were unaffected, because those hrefs are used verbatim.

Add an isExternalUrl helper to @hyperbook/types that matches any RFC 3986
scheme, and use it in the makeUrl implementations of the builder and the
VS Code preview. This covers mailto: and tel: as well as sms:, geo: and
friends, while https:// and data: keep working as before.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW

claude added 5 commits August 7, 2026 07:21
makeUrl only passed URLs through untouched when they contained "://" or
started with "data:". Every other scheme was treated as a relative path,
so a markdown link like [Write us](mailto:a@b.c) was joined with the base
path and rendered as href="/mailto:a@b.c". Links configured in
hyperbook.json were unaffected, because those hrefs are used verbatim.

Add an isExternalUrl helper to @hyperbook/types that matches any RFC 3986
scheme, and use it in the makeUrl implementations of the builder and the
VS Code preview. This covers mailto: and tel: as well as sms:, geo: and
friends, while https:// and data: keep working as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
Emojis were resolved to plain Unicode characters and drawn by whatever
emoji font the reader's operating system provides, so the same book looked
different on Windows, macOS, Android and Linux.

Add a rehypeEmoji plugin that swaps emojis for Twemoji images when
elements.emoji.style is set to "twemoji". It runs after the shell, so
icons configured in hyperbook.json are covered along with the content,
and it skips pre, code, script, style, textarea and title. Characters
that are text by default, like (c) or (tm), are only replaced when the
author asked for the emoji presentation, and an emoji without a Twemoji
asset is left as text.

The full Twemoji set ships in the package assets, but a build copies only
the images a book actually uses into its output, both for a full build
and for an incremental rebuild in the dev server. The default stays
"native", so existing books render exactly as before.

Twemoji graphics are CC-BY 4.0 by Twitter, Inc and other contributors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
A bookmark label was interpolated into the onclick attribute of the
bookmark button and rendered with innerHTML. That had three problems: a
heading containing a quote or a backslash produced a broken JavaScript
string and the button threw, the label was persisted markup that came
back through innerHTML, and the label was the markdown text rather than
what the page renders, so an emoji drawn as an image was a plain
character again in the bookmark list.

Labels are now read from the rendered heading when a bookmark is saved
and stored as parts, each with its text and, for an emoji, its id. The
bookmark list builds its entries from those parts with the DOM, so
nothing that was stored is parsed as HTML, emojis keep the look they
have on the page, and the id rather than a URL means a bookmark survives
a change of the basePath.

The button lost its inline onclick and is handled by one delegated
listener, which also covers headings that are added later. It carries
data-key, a data-label fallback and aria-pressed.

The store moves to version 6, which drops the pointless index on the
label and migrates existing labels to the new shape. A plain string
label is still rendered, so bookmarks from an older version and from an
older export keep working.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
The indicator was the 🔖 character in two places: as the content of the
button on a heading, and as the content of a ::before in the bookmark
list. Both were drawn with the emoji font of the reader, so the control
looked different on every platform. The one in the button also changed
into a Twemoji image once a hyperbook set the emoji style, which made a
piece of interface follow a content setting.

Both are now a mask over the feather bookmark icon, so the control looks
the same everywhere and stays a control. It takes the color of its
surroundings, which keeps it readable in light and dark mode, and a
bookmarked heading shows a filled icon instead of only a less
transparent one.

The button carries an aria-label now, since it no longer has content to
name it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
The icon inherited its color, which picked up the color of the h1 rather
than the color the heading appears in: the heading text is a link, and
the button is its sibling, so inheriting missed the brand color the
reader actually sees. Take the same color the heading link takes, which
also keeps the icon in step with the brand color of the hyperbook and
with the dark mode variant of it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperbook-4fwa Ready Ready Preview Aug 7, 2026 10:40am

Dogfoods the emoji style on the documentation, so the emojis in the
docs, the language flags of the library and the icons of the custom
links look the same for every reader.

Also fixes a crash the website build turned up: an element that carries
no children at all, which a directive can produce for a void element
like an img, made the emoji walk throw. It is skipped now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kkjvqifo7fQ5W6woRWiSW
@mikebarkmin
mikebarkmin merged commit 20de8fe into main Aug 7, 2026
3 checks passed
@mikebarkmin
mikebarkmin deleted the claude/hyperbook-mailto-tel-links-5rdklw branch August 7, 2026 10:42
@github-actions github-actions Bot mentioned this pull request Aug 7, 2026
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.

2 participants