Skip to content

v0.5.0

Choose a tag to compare

@xKeCo xKeCo released this 14 Aug 15:04
· 79 commits to main since this release

Single-page app support, one event stream for every change, and a pre-release
audit of the screenshot pipeline that turned up four separate ways a capture
disagreed with the page it was taken from.

npm install helldots@0.5.0

Single-page apps

notifyNavigation() re-syncs the widget after a client-side navigation:
comments reclassify against the new pathname, anchors re-resolve against the
new DOM, markers rebuild and the inbox moves onto the new page — deep links
and the cross-page handoff included. The new navigate option routes the
widget's own cross-page jumps through your router instead of a full reload,
and autoDetectNavigation: true covers back/forward automatically.

const overlay = createCommentOverlay({
  navigate: (page) => router.push(page),
});
router.afterEach(() => overlay.notifyNavigation());

One subscription for every change

onChange fires for every mutation, typed as a discriminated union on
event.type — handy when you sync everything to one endpoint instead of
wiring nine callbacks. The existing callbacks are unchanged and keep firing at
the same moments; this is additive. A handler that throws is now caught and
warned about instead of propagating out of the mutation that already happened.

Screenshots that match the page

A screenshot is not a screen grab — the browser exposes no way to rasterize
the painted page from JavaScript, so the capture is a re-render of the DOM,
and anything the re-render gets wrong moves content relative to what you saw.
Four such defects are fixed here:

  • The render was anchored to <body>, where the user-agent's 8px margin
    reappears, so every element in normal flow landed 8px off and the last 8px
    fell outside the canvas.
  • Pages shorter than the viewport came out with a solid black band where the
    render did not reach.
  • A strict style-src Content Security Policy killed the capture outright.
  • A web font served from a cross-origin stylesheet never reached the clone, so
    captured text reflowed into a fallback face — and its different metrics made
    drag selections over text come back holding the wrong glyphs.

That last one ships behind a new opt-in option, embedCrossOriginFonts. Most
pages want the cheaper fix instead: add crossorigin to the font <link>, or
self-host it. See Web fonts in screenshots in the README.

Also in this release

  • addReply accepts a comment id as well as the live object, and the new
    clearComments() wipes everything at once — the bulk reset for reconciling
    against a backend before a fresh loadComments.
  • The inbox detail's Context section folds away, like the thread popover's.
  • The widget renders under a strict style-src CSP: styles are delivered as
    constructed stylesheets.
  • Dropdowns open upward when there is no room below them.
  • Accessibility: the keyboard contract role="menu" promises, focus handling
    in the lightbox and inbox, and keyboard-operable screenshot thumbnails.
  • Performance: the inbox list reconciles by comment id instead of rebuilding,
    and keeps its scroll position.
  • Internals: overlay.js split into capture-flow, popover-controller and
    marker-engine. No public API change.

Upgrading from 0.4.0

No breaking changes.

Only if you pass a custom strings object: one new key, modifierShift
("Shift"). Nothing was removed. The bundled en and es locales are
complete.


Full list of changes in CHANGELOG.md.