@pixelmatters/markup 1.21.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,10 +12,10 @@ Pin-anchored feedback for live web apps. Drop in a script tag and your stakehold
12
12
  - **Threads, in real time.** Replies stream in via WebSocket. Per-comment edit, delete (with tombstones), and emoji reactions.
13
13
  - **@-mentions.** Typing `@` in the composer opens a project-member picker and inserts a chip; the `@[Name](userId)` wire format never reaches the screen. Mentioned teammates are notified, and signed-in users read those notifications from the toolbar's inbox.
14
14
  - **Annotated screenshots.** Opt-in capture with the pin marker drawn on the image and embedded fonts, so the snapshot matches what the user saw.
15
- - **Drop-in identity.** Anonymous by default, with a popup-based sign-in that survives Safari ITP and Chrome storage partitioning. Signed-in authors show their profile picture; everyone else gets initials.
15
+ - **Drop-in identity.** Anonymous by default, with a popup-based sign-in that survives Safari ITP and Chrome storage partitioning. Signed-in authors show their profile picture; everyone else gets initials. A project can be set to **members only** in the dashboard, in which case visitors are asked to sign in before commenting; everyone still sees the pins.
16
16
  - **Agent replies are labelled.** A comment written by an AI agent through Markup's MCP server carries a bot badge. It's posted under a team member's name, so the badge is the only way a visitor can tell a machine answered.
17
17
  - **Style-isolated.** Runs inside an open shadow root with `:host { all: initial }`, so host CSS can't bleed in and widget CSS can't bleed out.
18
- - **SPA-aware.** Patches `history.pushState` / `replaceState` and follows `popstate` to refresh threads on route changes.
18
+ - **SPA-aware.** Patches `history.pushState` / `replaceState` and follows `popstate` and `hashchange` to refresh threads on route changes. Hash routers are supported: a `#/orders` path is part of the route a thread is filed under, while a plain `#section` anchor is not, and neither is a query string in either position — `#/orders?tab=2` and `#/orders` are one page, as `/orders?tab=2` and `/orders` already were.
19
19
  - **Respects the platform.** Honours `prefers-reduced-motion` and `prefers-color-scheme`, with full keyboard navigation and focus traps in popovers.
20
20
  - **Tiny API, tiny config.** `init({ apiUrl, apiKey })` is enough to start. No global CSS to import, no provider to wrap.
21
21
 
@@ -37,9 +37,9 @@ CDN drop-in, no build step. Paste this just before `</body>`:
37
37
  ```html
38
38
  <script type="module">
39
39
  // Pin the exact version; esm.sh resolves it from npm
40
- import { init } from 'https://esm.sh/@pixelmatters/markup@1.21.0'
40
+ import { init } from 'https://esm.sh/@pixelmatters/markup@1.23.0'
41
41
  // or
42
- // import { init } from 'https://esm.run/@pixelmatters/markup@1.21.0'
42
+ // import { init } from 'https://esm.run/@pixelmatters/markup@1.23.0'
43
43
 
44
44
  init({
45
45
  apiUrl: 'https://your-deployment.convex.site',
@@ -50,14 +50,14 @@ CDN drop-in, no build step. Paste this just before `</body>`:
50
50
  </script>
51
51
  ```
52
52
 
53
- > **Why pin the version?** CDN URLs without a version (`@pixelmatters/markup`) resolve to whatever's `latest` on npm, so a future major release will break your page with no warning. Always pin (`@pixelmatters/markup@1.21.0`).
53
+ > **Why pin the version?** CDN URLs without a version (`@pixelmatters/markup`) resolve to whatever's `latest` on npm, so a future major release will break your page with no warning. Always pin (`@pixelmatters/markup@1.23.0`).
54
54
 
55
55
  If your platform doesn't allow inline JS (some CMS / page-builder editors), use the auto-init form instead. Point a `<script src=…>` at the bundle and pass config via `data-*` attributes:
56
56
 
57
57
  ```html
58
58
  <script
59
59
  type="module"
60
- src="https://esm.sh/@pixelmatters/markup@1.21.0"
60
+ src="https://esm.sh/@pixelmatters/markup@1.23.0"
61
61
  data-markup-widget="true"
62
62
  data-api-url="https://your-deployment.convex.site"
63
63
  data-api-key="markup_..."
@@ -281,7 +281,7 @@ Capture degrades instead of failing outright:
281
281
  - The widget mounts `<div id="markup-widget">` on `document.body` and attaches an open shadow root.
282
282
  - All UI lives in that shadow root, with `:host { all: initial }` blocking style inheritance.
283
283
  - The host element is `position: fixed; inset: 0; pointer-events: none`, so the widget paints over the entire viewport without blocking the host's clicks; only the toolbar and active popovers opt back in to pointer events.
284
- - Pins are anchored as `(x, y)` fractions of the document plus a best-effort CSS selector (via [`@medv/finder`](https://github.com/antonmedv/finder)). The selector wins when it still resolves; the fraction is the fallback so pins survive layout changes.
284
+ - Pins are anchored as `(x, y)` fractions of the document plus a CSS path from the nearest landmark (a stable `id`, `data-testid`, `main`, `form`, `table`, …) and the element's text. The path wins when it still resolves, relaxing from the top if a wrapper changed, and a match whose text differs is rejected; the fraction is the fallback so pins survive layout changes.
285
285
  - Live thread updates come over a WebSocket to the deployment's `*.convex.cloud` origin, which the widget derives from `apiUrl`. Everything else, meaning comments, identity, screenshots and error reports, goes to `*.convex.site` over HTTP.
286
286
  - Identity lives in **host-page** `localStorage` under `markup.identity`, keyed to the top-level site. On first load the widget mints a server-signed anonymous JWT via `POST /widget/anon-identity` so the backend can verify the `authorClientId` on every anon write. Tampering with the cached `clientId` invalidates the signature. Verified identities upgrade to a `Bearer` JWT via the popup flow described below.
287
287
 
@@ -372,7 +372,7 @@ For a `<script>` tag drop-in (no bundler), use the inline ESM form and **pin the
372
372
 
373
373
  ```html
374
374
  <script type="module">
375
- import { init } from 'https://esm.sh/@pixelmatters/markup@1.21.0'
375
+ import { init } from 'https://esm.sh/@pixelmatters/markup@1.23.0'
376
376
 
377
377
  init({
378
378
  apiUrl: '...',
@@ -388,7 +388,7 @@ If inline JS is disallowed (some CMS / page-builder editors), use the auto-init
388
388
  ```html
389
389
  <script
390
390
  type="module"
391
- src="https://esm.sh/@pixelmatters/markup@1.21.0"
391
+ src="https://esm.sh/@pixelmatters/markup@1.23.0"
392
392
  data-markup-widget="true"
393
393
  data-api-url="..."
394
394
  data-api-key="..."