@pixelmatters/markup 1.2.0 → 1.3.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
@@ -17,25 +17,45 @@ Pin-anchored feedback for live web apps. Drop in a script tag (or one React comp
17
17
  - **Respects the platform** — honours `prefers-reduced-motion` and `prefers-color-scheme`; full keyboard navigation with focus traps in popovers.
18
18
  - **Tiny surface, tiny config** — `init({ apiUrl, apiKey })` is enough to start. No global CSS to import, no provider to wrap.
19
19
 
20
- Built with [Preact](https://preactjs.com). Ships as ESM with a vanilla entry and a React/Preact wrapper.
20
+ Built with [Preact](https://preactjs.com). Ships as a single ESM bundle — wire it into any framework with a one-liner in your root component (snippets below).
21
21
 
22
22
  ## Install
23
23
 
24
24
  ```bash
25
25
  # pnpm
26
- pnpm install @pixelmatters/markup
26
+ pnpm add @pixelmatters/markup
27
27
  # or yarn
28
28
  yarn add @pixelmatters/markup
29
29
  # or npm
30
30
  npm install @pixelmatters/markup
31
31
  ```
32
32
 
33
- CDN drop-in (auto-init on `DOMContentLoaded`):
33
+ CDN drop-in (no build step) — paste this just before `</body>`:
34
+
35
+ ```html
36
+ <script type="module">
37
+ // Pin the exact version — esm.sh resolves it from npm
38
+ import { init } from 'https://esm.sh/@pixelmatters/markup@1.3.0'
39
+ // or
40
+ // import { init } from 'https://esm.run/@pixelmatters/markup@1.3.0'
41
+
42
+ init({
43
+ apiUrl: 'https://your-deployment.convex.site',
44
+ apiKey: 'markup_...',
45
+ position: 'bottom-right', // optional
46
+ theme: 'auto', // optional
47
+ })
48
+ </script>
49
+ ```
50
+
51
+ > **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.3.0`).
52
+
53
+ 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:
34
54
 
35
55
  ```html
36
56
  <script
37
57
  type="module"
38
- src="https://unpkg.com/@pixelmatters/markup"
58
+ src="https://esm.sh/@pixelmatters/markup@1.3.0"
39
59
  data-markup-widget="true"
40
60
  data-api-url="https://your-deployment.convex.site"
41
61
  data-api-key="markup_..."
@@ -43,7 +63,7 @@ CDN drop-in (auto-init on `DOMContentLoaded`):
43
63
  ></script>
44
64
  ```
45
65
 
46
- The `data-markup-widget="true"` attribute is required — it's how the bootstrap locates its own `<script>` tag (since `document.currentScript` is `null` for `type="module"`).
66
+ `data-markup-widget="true"` is required — it's how the bootstrap finds its own `<script>` tag (since `document.currentScript` is `null` for `type="module"`).
47
67
 
48
68
  ## Quickstart
49
69
 
@@ -63,23 +83,60 @@ const stop = init({
63
83
  stop() // equivalent to destroy()
64
84
  ```
65
85
 
66
- ### React / Preact
86
+ ### React
67
87
 
68
88
  ```tsx
69
- import { MarkupWidget } from '@pixelmatters/markup/react'
89
+ import { useEffect } from 'react'
90
+ import { init } from '@pixelmatters/markup'
70
91
 
71
92
  export default function App() {
72
- return (
73
- <>
74
- {/* your app */}
75
- <MarkupWidget
76
- apiUrl={import.meta.env.VITE_MARKUP_API_URL}
77
- apiKey={import.meta.env.VITE_MARKUP_API_KEY}
78
- position="bottom-right" // optional
79
- theme="light" // optional
80
- />
81
- </>
82
- )
93
+ useEffect(() => {
94
+ return init({
95
+ apiUrl: import.meta.env.VITE_MARKUP_API_URL,
96
+ apiKey: import.meta.env.VITE_MARKUP_API_KEY,
97
+ position: 'bottom-right', // optional
98
+ theme: 'auto', // optional
99
+ })
100
+ }, [])
101
+
102
+ return <>{/* your app */}</>
103
+ }
104
+ ```
105
+
106
+ ### Vue 3
107
+
108
+ ```vue
109
+ <script setup lang="ts">
110
+ import { onMounted, onBeforeUnmount } from 'vue'
111
+ import { init } from '@pixelmatters/markup'
112
+
113
+ let stop: (() => void) | undefined
114
+ onMounted(() => {
115
+ stop = init({
116
+ apiUrl: import.meta.env.VITE_MARKUP_API_URL,
117
+ apiKey: import.meta.env.VITE_MARKUP_API_KEY,
118
+ })
119
+ })
120
+ onBeforeUnmount(() => stop?.())
121
+ </script>
122
+ ```
123
+
124
+ ### SolidJS
125
+
126
+ ```tsx
127
+ import { onMount, onCleanup } from 'solid-js'
128
+ import { init } from '@pixelmatters/markup'
129
+
130
+ export default function App() {
131
+ onMount(() => {
132
+ const stop = init({
133
+ apiUrl: import.meta.env.VITE_MARKUP_API_URL,
134
+ apiKey: import.meta.env.VITE_MARKUP_API_KEY,
135
+ })
136
+ onCleanup(stop)
137
+ })
138
+
139
+ return <>{/* your app */}</>
83
140
  }
84
141
  ```
85
142
 
@@ -156,8 +213,6 @@ A drop-in feedback widget published on npm as `@pixelmatters/markup`. It mounts
156
213
 
157
214
  ```ts
158
215
  import { init, destroy } from '@pixelmatters/markup'
159
- // or:
160
- import { MarkupWidget } from '@pixelmatters/markup/react'
161
216
 
162
217
  init({
163
218
  apiUrl: string, // required
@@ -167,12 +222,32 @@ init({
167
222
  }) // returns a destroy() function — call it on unmount / logout / route teardown
168
223
  ```
169
224
 
170
- For a `<script>` tag drop-in (no bundler), use:
225
+ For React/Vue/Solid hosts, call `init()` from a mount lifecycle hook
226
+ (`useEffect`, `onMounted`, `onMount`) and call the returned `destroy` on
227
+ cleanup. There's no framework-specific entrypoint — `init` is the entire
228
+ public surface.
229
+
230
+ For a `<script>` tag drop-in (no bundler), use the inline ESM form and **pin the version**:
231
+
232
+ ```html
233
+ <script type="module">
234
+ import { init } from 'https://esm.sh/@pixelmatters/markup@1.3.0'
235
+
236
+ init({
237
+ apiUrl: '...',
238
+ apiKey: '...',
239
+ position: 'bottom-right',
240
+ theme: 'auto',
241
+ })
242
+ </script>
243
+ ```
244
+
245
+ If inline JS is disallowed (some CMS / page-builder editors), use the auto-init `<script src=…>` form with `data-*` attributes (`data-markup-widget="true"` is required):
171
246
 
172
247
  ```html
173
248
  <script
174
249
  type="module"
175
- src="https://unpkg.com/@pixelmatters/markup"
250
+ src="https://esm.sh/@pixelmatters/markup@1.3.0"
176
251
  data-markup-widget="true"
177
252
  data-api-url="..."
178
253
  data-api-key="..."
@@ -180,8 +255,6 @@ For a `<script>` tag drop-in (no bundler), use:
180
255
  ></script>
181
256
  ```
182
257
 
183
- The `data-markup-widget="true"` attribute is required.
184
-
185
258
  ## Your task
186
259
 
187
260
  1. Detect my framework (React, Vue, Svelte, Next.js, plain HTML, etc.) by inspecting the project.
@@ -195,7 +268,7 @@ Constraints:
195
268
 
196
269
  - Do **not** add CSS imports or provider components — the widget needs neither.
197
270
  - Do **not** hardcode the key.
198
- - If the project has a CSP, add `https://unpkg.com` to `script-src` only if I'm using the `<script>` tag path.
271
+ - If the project has a CSP, add `https://esm.sh` to `script-src` only if I'm using the `<script>` tag path.
199
272
  ````
200
273
 
201
274
  ## Browser support
@@ -206,7 +279,7 @@ Modern evergreen browsers (Chrome, Edge, Firefox, Safari) and their mobile equiv
206
279
 
207
280
  ```bash
208
281
  pnpm dev # vite dev server with the playground page
209
- pnpm build # production build → dist/{widget,react}.{js,d.ts}
282
+ pnpm build # production build → dist/widget.{js,d.ts}
210
283
  pnpm typecheck # tsc --noEmit
211
284
  ```
212
285
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelmatters/markup",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Embeddable feedback widget for collecting visual bug reports, screenshots, and comments on live web apps.",
5
5
  "keywords": [
6
6
  "annotation",
@@ -26,8 +26,6 @@
26
26
  "files": [
27
27
  "dist/widget.js",
28
28
  "dist/widget.d.ts",
29
- "dist/react.js",
30
- "dist/react.d.ts",
31
29
  "README.md",
32
30
  "LICENSE"
33
31
  ],
@@ -38,10 +36,7 @@
38
36
  "types": "./dist/widget.d.ts",
39
37
  "import": "./dist/widget.js"
40
38
  },
41
- "./react": {
42
- "types": "./dist/react.d.ts",
43
- "import": "./dist/react.js"
44
- }
39
+ "./package.json": "./package.json"
45
40
  },
46
41
  "publishConfig": {
47
42
  "access": "public",
@@ -50,7 +45,6 @@
50
45
  "devDependencies": {
51
46
  "@medv/finder": "^4.0.2",
52
47
  "@preact/preset-vite": "^2.10.5",
53
- "@types/react": "^19.2.14",
54
48
  "convex": "^1.37.0",
55
49
  "html-to-image": "^1.11.13",
56
50
  "preact": "^10.25.0",
@@ -58,23 +52,11 @@
58
52
  "vite": "^8.0.11",
59
53
  "vite-plugin-dts": "^5.0.0"
60
54
  },
61
- "peerDependencies": {
62
- "react": "^18.0.0 || ^19.0.0",
63
- "react-dom": "^18.0.0 || ^19.0.0"
64
- },
65
- "peerDependenciesMeta": {
66
- "react": {
67
- "optional": true
68
- },
69
- "react-dom": {
70
- "optional": true
71
- }
72
- },
73
55
  "engines": {
74
56
  "node": ">=18"
75
57
  },
76
58
  "scripts": {
77
- "build": "vite build --mode widget && vite build --mode react && rm -rf dist/runtime",
59
+ "build": "vite build && rm -rf dist/runtime",
78
60
  "dev": "vite",
79
61
  "typecheck": "tsc --noEmit"
80
62
  }
package/dist/react.d.ts DELETED
@@ -1,21 +0,0 @@
1
- import { WidgetTheme } from './widget';
2
- export interface MarkupWidgetProps {
3
- /** Convex deployment site URL, e.g. `https://your-deployment.convex.site` */
4
- apiUrl: string;
5
- /** Raw API key minted from a project's settings page */
6
- apiKey: string;
7
- /** Where the floating button sits. Defaults to bottom-right. */
8
- position?: 'bottom-right' | 'bottom-left';
9
- /** 'light' | 'dark' | 'auto' (default 'auto' — follow prefers-color-scheme) */
10
- theme?: WidgetTheme;
11
- }
12
- /**
13
- * React-host entrypoint. Renders nothing — the actual UI mounts itself into
14
- * a sibling shadow DOM at `document.body` so it never tangles with the host
15
- * tree's CSS.
16
- *
17
- * `useEffect` is imported from `react`, which the consumer's bundler
18
- * resolves: real React in a React app, or `preact/hooks` re-exported via
19
- * `preact/compat` in a Preact app that has aliased `react` → `preact/compat`.
20
- */
21
- export declare function MarkupWidget(props: MarkupWidgetProps): null;