@pixelmatters/markup 1.4.0 → 1.5.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
@@ -35,9 +35,9 @@ CDN drop-in (no build step) — paste this just before `</body>`:
35
35
  ```html
36
36
  <script type="module">
37
37
  // Pin the exact version — esm.sh resolves it from npm
38
- import { init } from 'https://esm.sh/@pixelmatters/markup@1.4.0'
38
+ import { init } from 'https://esm.sh/@pixelmatters/markup@1.5.0'
39
39
  // or
40
- // import { init } from 'https://esm.run/@pixelmatters/markup@1.4.0'
40
+ // import { init } from 'https://esm.run/@pixelmatters/markup@1.5.0'
41
41
 
42
42
  init({
43
43
  apiUrl: 'https://your-deployment.convex.site',
@@ -49,14 +49,14 @@ CDN drop-in (no build step) — paste this just before `</body>`:
49
49
  </script>
50
50
  ```
51
51
 
52
- > **Why pin the version?** CDN URLs without a version (`@pixelmatters/markup`) resolve to whatever's `latest` on npm — a future major release will break your page silently. Always pin (`@pixelmatters/markup@1.4.0`).
52
+ > **Why pin the version?** CDN URLs without a version (`@pixelmatters/markup`) resolve to whatever's `latest` on npm — a future major release will break your page silently. Always pin (`@pixelmatters/markup@1.5.0`).
53
53
 
54
54
  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:
55
55
 
56
56
  ```html
57
57
  <script
58
58
  type="module"
59
- src="https://esm.sh/@pixelmatters/markup@1.4.0"
59
+ src="https://esm.sh/@pixelmatters/markup@1.5.0"
60
60
  data-markup-widget="true"
61
61
  data-api-url="https://your-deployment.convex.site"
62
62
  data-api-key="markup_..."
@@ -178,6 +178,34 @@ Unmounts the widget and removes the host element. Safe to call when nothing is m
178
178
  | Drag the FAB | Snap it to whichever bottom corner the pointer ends in |
179
179
  | Drag a popover header | Move the open thread / new-thread popover; resets to the pin on reopen |
180
180
 
181
+ ## Screenshots & privacy
182
+
183
+ By default, the widget captures the visible viewport as a JPEG before you submit a thread. Sensitive fields are blacked out **before** the image is produced — the live DOM is mutated only for the duration of the capture and immediately restored. No image content leaves the browser until the user explicitly attaches the screenshot and posts.
184
+
185
+ **Auto-scrubbed (zero config):**
186
+
187
+ - `input[type="password"]`
188
+ - Any `<input>` whose `autocomplete` attribute contains `cc-number`, `cc-csc`, `cc-exp`, `cc-name`, `cc-type`, `current-password`, `new-password`, or `one-time-code`
189
+
190
+ **Attribute API** — add to any element to control capture:
191
+
192
+ | Attribute | Behaviour |
193
+ | --------------------- | ---------------------------------------------------------------------- |
194
+ | `data-markup-private` | Always mask — contents replaced with a solid block. |
195
+ | `data-markup-redact` | Alias for `data-markup-private`. |
196
+ | `data-markup-safe` | Exempts descendants from the default auto-detect rules (escape hatch). |
197
+ | `data-markup-skip` | Removes the element from the screenshot entirely. |
198
+
199
+ **`init()` `screenshots` config:**
200
+
201
+ | Option | Type | Default | Description |
202
+ | ---------------------------- | --------- | ------- | ---------------------------------------------------------- |
203
+ | `screenshots.enabled` | `boolean` | `true` | Set to `false` to disable capture entirely. |
204
+ | `screenshots.strictScrub` | `boolean` | `false` | Also masks all `input`, `select`, and `textarea` elements. |
205
+ | `screenshots.redactSelector` | `string` | — | Custom CSS selector — matched elements are always masked. |
206
+
207
+ When a screenshot is attached in the composer, a chip shows how many fields were redacted. Clicking it expands the list of CSS selectors that were masked.
208
+
181
209
  ## How it works
182
210
 
183
211
  - The widget mounts `<div id="markup-widget">` on `document.body` and attaches an open shadow root.
@@ -244,7 +272,7 @@ For a `<script>` tag drop-in (no bundler), use the inline ESM form and **pin the
244
272
 
245
273
  ```html
246
274
  <script type="module">
247
- import { init } from 'https://esm.sh/@pixelmatters/markup@1.4.0'
275
+ import { init } from 'https://esm.sh/@pixelmatters/markup@1.5.0'
248
276
 
249
277
  init({
250
278
  apiUrl: '...',
@@ -261,7 +289,7 @@ If inline JS is disallowed (some CMS / page-builder editors), use the auto-init
261
289
  ```html
262
290
  <script
263
291
  type="module"
264
- src="https://esm.sh/@pixelmatters/markup@1.4.0"
292
+ src="https://esm.sh/@pixelmatters/markup@1.5.0"
265
293
  data-markup-widget="true"
266
294
  data-api-url="..."
267
295
  data-api-key="..."
package/dist/widget.d.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  export type WidgetTheme = 'light' | 'dark' | 'auto';
2
2
  export type WidgetFab = 'default' | 'icon-only';
3
+ export interface ScreenshotsConfig {
4
+ /** Disable screenshot capture entirely. Default: enabled. */
5
+ enabled?: boolean;
6
+ /** Also masks all inputs/selects/textareas in addition to the default sensitive set. Default: false. */
7
+ strictScrub?: boolean;
8
+ /** Custom CSS selector — matched elements are always masked. */
9
+ redactSelector?: string;
10
+ }
3
11
  export interface WidgetConfig {
4
12
  /** Convex deployment site URL, e.g. `https://your-deployment.convex.site` */
5
13
  apiUrl: string;
@@ -22,6 +30,8 @@ export interface WidgetConfig {
22
30
  * Defaults to `'default'`.
23
31
  */
24
32
  fab?: WidgetFab;
33
+ /** Screenshot capture and PII-scrub options. */
34
+ screenshots?: ScreenshotsConfig;
25
35
  }
26
36
  /**
27
37
  * Mounts the feedback widget on the page. Idempotent — calling init again