@pixelmatters/markup 1.27.3 → 1.28.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 +72 -34
- package/dist/react.d.ts +21 -0
- package/dist/react.js +15 -0
- package/dist/react.js.map +1 -0
- package/dist/shared-mount-DABK4arh.js +27 -0
- package/dist/shared-mount-DABK4arh.js.map +1 -0
- package/dist/vue.d.ts +23 -0
- package/dist/vue.js +21 -0
- package/dist/vue.js.map +1 -0
- package/dist/widget.js +1875 -1782
- package/dist/widget.js.map +1 -1
- package/package.json +31 -6
- package/skills/install-markup-widget/SKILL.md +47 -36
package/README.md
CHANGED
|
@@ -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.
|
|
40
|
+
import { init } from 'https://esm.sh/@pixelmatters/markup@1.28.0'
|
|
41
41
|
// or
|
|
42
|
-
// import { init } from 'https://esm.run/@pixelmatters/markup@1.
|
|
42
|
+
// import { init } from 'https://esm.run/@pixelmatters/markup@1.28.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.
|
|
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.28.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.
|
|
60
|
+
src="https://esm.sh/@pixelmatters/markup@1.28.0"
|
|
61
61
|
data-markup-widget="true"
|
|
62
62
|
data-api-url="https://your-deployment.convex.site"
|
|
63
63
|
data-api-key="markup_..."
|
|
@@ -88,44 +88,53 @@ stop() // tears down this instance; the exported destroy() tears down whichever
|
|
|
88
88
|
|
|
89
89
|
### React
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
import { useEffect } from 'react'
|
|
93
|
-
import { init } from '@pixelmatters/markup'
|
|
91
|
+
React 18 or later. Render the component once near your app root:
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
apiUrl: import.meta.env.VITE_MARKUP_API_URL,
|
|
99
|
-
apiKey: import.meta.env.VITE_MARKUP_API_KEY,
|
|
100
|
-
position: 'bottom-right', // optional: 'bottom-right' | 'bottom-left' | 'bottom-center'
|
|
101
|
-
theme: 'auto', // optional: 'auto' | 'light' | 'dark'
|
|
102
|
-
})
|
|
103
|
-
}, [])
|
|
93
|
+
```tsx
|
|
94
|
+
'use client' // Next.js App Router only
|
|
95
|
+
import { useMarkup } from '@pixelmatters/markup/react'
|
|
104
96
|
|
|
105
|
-
|
|
97
|
+
export function Markup() {
|
|
98
|
+
useMarkup({
|
|
99
|
+
apiUrl: import.meta.env.VITE_MARKUP_API_URL,
|
|
100
|
+
apiKey: import.meta.env.VITE_MARKUP_API_KEY,
|
|
101
|
+
position: 'bottom-right', // optional: 'bottom-right' | 'bottom-left' | 'bottom-center'
|
|
102
|
+
theme: 'auto', // optional: 'auto' | 'light' | 'dark'
|
|
103
|
+
enabled: true, // optional: false unmounts it, e.g. from your build environment
|
|
104
|
+
})
|
|
105
|
+
return null
|
|
106
106
|
}
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
The hook takes the same options as `init()`, plus `enabled`. An inline object
|
|
110
|
+
is fine: the widget remounts only when a value changes. StrictMode's double
|
|
111
|
+
mount leaves one widget, two components with the same options share it until
|
|
112
|
+
both unmount, and server rendering mounts nothing. Don't also call `init()` on
|
|
113
|
+
the same page.
|
|
114
|
+
|
|
109
115
|
### Vue 3
|
|
110
116
|
|
|
117
|
+
Vue 3.3 or later. Call it once from your root component:
|
|
118
|
+
|
|
111
119
|
```vue
|
|
112
120
|
<script setup lang="ts">
|
|
113
|
-
import {
|
|
114
|
-
import { init } from '@pixelmatters/markup'
|
|
121
|
+
import { useMarkup } from '@pixelmatters/markup/vue'
|
|
115
122
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
position: 'bottom-right', // optional: 'bottom-right' | 'bottom-left' | 'bottom-center'
|
|
122
|
-
theme: 'auto', // optional: 'auto' | 'light' | 'dark'
|
|
123
|
-
})
|
|
123
|
+
useMarkup({
|
|
124
|
+
apiUrl: import.meta.env.VITE_MARKUP_API_URL,
|
|
125
|
+
apiKey: import.meta.env.VITE_MARKUP_API_KEY,
|
|
126
|
+
position: 'bottom-right', // optional: 'bottom-right' | 'bottom-left' | 'bottom-center'
|
|
127
|
+
theme: 'auto', // optional: 'auto' | 'light' | 'dark'
|
|
124
128
|
})
|
|
125
|
-
onBeforeUnmount(() => stop?.())
|
|
126
129
|
</script>
|
|
127
130
|
```
|
|
128
131
|
|
|
132
|
+
The composable takes the same options as `init()`, plus `enabled`, as a plain
|
|
133
|
+
object, a ref or a getter (`() => ({ …, theme: theme.value })`), and remounts
|
|
134
|
+
the widget only when a value changes. Two components with the same options
|
|
135
|
+
share one widget until both unmount, and nothing mounts during server
|
|
136
|
+
rendering.
|
|
137
|
+
|
|
129
138
|
### SolidJS
|
|
130
139
|
|
|
131
140
|
```tsx
|
|
@@ -231,6 +240,12 @@ have on. A pin's tooltip names the URL it was left on either way.
|
|
|
231
240
|
|
|
232
241
|
**Show resolved threads** is off by default. Turned on, the widget also renders the route's most recently resolved threads (up to 100) as muted check-mark pins. Opening one shows the thread read-only: no replies, edits, reactions or resolve button. Reopening still happens from the dashboard.
|
|
233
242
|
|
|
243
|
+
A thread's own **⋯** menu has **Copy link**, and for signed-in users
|
|
244
|
+
**Copy for agent**: the thread as a Markdown prompt for a coding agent, with
|
|
245
|
+
the page, element, declared source path and every comment. Comment text is
|
|
246
|
+
quoted line by line and every other value is a quoted string, so what a
|
|
247
|
+
visitor typed can't pass itself off as part of the instructions.
|
|
248
|
+
|
|
234
249
|
The last two menu rows open inside the menu itself, replacing the rows with a
|
|
235
250
|
reading panel and a **Back** button. `Esc` steps back to the rows, and again to
|
|
236
251
|
close.
|
|
@@ -361,6 +376,29 @@ share a route, each pin's tooltip names the URL it was left on, and the
|
|
|
361
376
|
overflow menu's **Only this URL's pins** narrows the page to one view without
|
|
362
377
|
changing how anything is stored.
|
|
363
378
|
|
|
379
|
+
## Anchors and source paths
|
|
380
|
+
|
|
381
|
+
Two optional attributes make pins sturdier and give agents a place to start.
|
|
382
|
+
Neither is required; without them the widget anchors by structure and text.
|
|
383
|
+
|
|
384
|
+
```html
|
|
385
|
+
<section data-markup-anchor="pricing" data-markup-source="src/components/Pricing.tsx">…</section>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
| Attribute | What it does |
|
|
389
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
390
|
+
| `data-markup-anchor` | A stable name for the element, used ahead of ids and test attributes when a pin's selector is built. Treat it like an id: a name unique on the page addresses the element on its own, and a pin placed on it stays attached when its text changes. A name several elements share (`edit` on every row's button) is kept only as a hint alongside the element's position. In a list that can be reordered, name each item (`data-markup-anchor="todo-42"`) so a pin follows its item rather than its position. |
|
|
391
|
+
| `data-markup-source` | A repository-relative path. The nearest one above the pinned element is stored with the thread, shown in the dashboard, and returned to agents by the MCP server's `get_thread` as `anchorSource`. Values over 512 characters are ignored. |
|
|
392
|
+
|
|
393
|
+
Without a name, a pin in a list that was reordered or filtered still finds
|
|
394
|
+
its item when the pinned text is unique in the list, such as a title. It can't
|
|
395
|
+
tell identical controls apart: a pin on one of several **Edit** buttons stays
|
|
396
|
+
with whichever row now holds its old position. Name the items to cover that
|
|
397
|
+
case.
|
|
398
|
+
|
|
399
|
+
Both are read from your page as it is, so keep them accurate: an agent is told
|
|
400
|
+
to start from `anchorSource` and confirm it, not to trust it blindly.
|
|
401
|
+
|
|
364
402
|
## How it works
|
|
365
403
|
|
|
366
404
|
- The widget mounts `<div id="markup-widget">` on `document.body` and attaches an open shadow root.
|
|
@@ -448,16 +486,16 @@ init({
|
|
|
448
486
|
|
|
449
487
|
There is no `fab` option any more. It's accepted, ignored, and warns once. Drop it if you find one in my config.
|
|
450
488
|
|
|
451
|
-
For React
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
489
|
+
For React or Vue, use `useMarkup` from `@pixelmatters/markup/react` or
|
|
490
|
+
`@pixelmatters/markup/vue` once near the app root. For Solid and others, call
|
|
491
|
+
`init()` from a mount lifecycle hook (`onMount`) and call the returned
|
|
492
|
+
`destroy` on cleanup.
|
|
455
493
|
|
|
456
494
|
For a `<script>` tag drop-in (no bundler), use the inline ESM form and **pin the version**:
|
|
457
495
|
|
|
458
496
|
```html
|
|
459
497
|
<script type="module">
|
|
460
|
-
import { init } from 'https://esm.sh/@pixelmatters/markup@1.
|
|
498
|
+
import { init } from 'https://esm.sh/@pixelmatters/markup@1.28.0'
|
|
461
499
|
|
|
462
500
|
init({
|
|
463
501
|
apiUrl: '...',
|
|
@@ -473,7 +511,7 @@ If inline JS is disallowed (some CMS / page-builder editors), use the auto-init
|
|
|
473
511
|
```html
|
|
474
512
|
<script
|
|
475
513
|
type="module"
|
|
476
|
-
src="https://esm.sh/@pixelmatters/markup@1.
|
|
514
|
+
src="https://esm.sh/@pixelmatters/markup@1.28.0"
|
|
477
515
|
data-markup-widget="true"
|
|
478
516
|
data-api-url="..."
|
|
479
517
|
data-api-key="..."
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WidgetConfig } from './widget';
|
|
2
|
+
export type { WidgetConfig } from './widget';
|
|
3
|
+
export type UseMarkupOptions = WidgetConfig & {
|
|
4
|
+
/**
|
|
5
|
+
* `false` unmounts the widget, or never mounts it. Drive it from your build
|
|
6
|
+
* environment to keep the widget off production.
|
|
7
|
+
*
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Mounts the widget for as long as the calling component is mounted. Call it
|
|
14
|
+
* once near your app root.
|
|
15
|
+
*
|
|
16
|
+
* An inline options object is fine: the widget remounts only when a value
|
|
17
|
+
* changes, not when the object is recreated. Two components using the same
|
|
18
|
+
* options share one widget, and it stays until both unmount. Server rendering
|
|
19
|
+
* mounts nothing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useMarkup(options: UseMarkupOptions): void;
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { init as e, t } from "./widget.js";
|
|
3
|
+
import { t as n } from "./shared-mount-DABK4arh.js";
|
|
4
|
+
import { useEffect as r } from "react";
|
|
5
|
+
//#region src/react.ts
|
|
6
|
+
function i(i) {
|
|
7
|
+
let { enabled: a = !0, ...o } = i, s = a ? t(o) : null;
|
|
8
|
+
r(() => {
|
|
9
|
+
if (s !== null) return n(s, e);
|
|
10
|
+
}, [s]);
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { i as useMarkup };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","names":[],"sources":["../src/react.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\n\nimport { configKey } from './runtime/config-key'\nimport { acquireMount } from './runtime/shared-mount'\nimport { init, type WidgetConfig } from './widget'\n\nexport type { WidgetConfig } from './widget'\n\nexport type UseMarkupOptions = WidgetConfig & {\n /**\n * `false` unmounts the widget, or never mounts it. Drive it from your build\n * environment to keep the widget off production.\n *\n * @default true\n */\n enabled?: boolean\n}\n\n/**\n * Mounts the widget for as long as the calling component is mounted. Call it\n * once near your app root.\n *\n * An inline options object is fine: the widget remounts only when a value\n * changes, not when the object is recreated. Two components using the same\n * options share one widget, and it stays until both unmount. Server rendering\n * mounts nothing.\n */\nexport function useMarkup(options: UseMarkupOptions): void {\n const { enabled = true, ...config } = options\n const key = enabled ? configKey(config) : null\n\n useEffect(() => {\n if (key === null) return\n return acquireMount(key, init)\n }, [key])\n}\n"],"mappings":";;;;;AA6BA,SAAgB,EAAU,GAAiC;CACzD,IAAM,EAAE,aAAU,IAAM,GAAG,MAAW,GAChC,IAAM,IAAU,EAAU,CAAM,IAAI;CAE1C,QAAgB;EACV,UAAQ,MACZ,OAAO,EAAa,GAAK,CAAI;CAC/B,GAAG,CAAC,CAAG,CAAC;AACV"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/runtime/shared-mount.ts
|
|
2
|
+
var e = /* @__PURE__ */ new Map();
|
|
3
|
+
function t(t, n) {
|
|
4
|
+
let r = n(JSON.parse(t)), i = (e.get(t)?.count ?? 0) + 1;
|
|
5
|
+
e.delete(t), e.set(t, {
|
|
6
|
+
count: i,
|
|
7
|
+
dispose: r
|
|
8
|
+
});
|
|
9
|
+
let a = !1;
|
|
10
|
+
return () => {
|
|
11
|
+
if (a) return;
|
|
12
|
+
a = !0;
|
|
13
|
+
let r = e.get(t);
|
|
14
|
+
if (!r || (--r.count, r.count > 0)) return;
|
|
15
|
+
e.delete(t), r.dispose();
|
|
16
|
+
let i = [...e.entries()].at(-1);
|
|
17
|
+
if (i) try {
|
|
18
|
+
i[1].dispose = n(JSON.parse(i[0]));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
i[1].dispose = () => {}, console.warn("[markup] could not remount the widget", e);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { t };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=shared-mount-DABK4arh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-mount-DABK4arh.js","names":[],"sources":["../src/runtime/shared-mount.ts"],"sourcesContent":["import type { WidgetConfig } from '../widget'\n\ntype Holder = { count: number; dispose: () => void }\n\nconst holders = new Map<string, Holder>()\n\n/**\n * Counts hook holders per config, so the first of two components to unmount\n * doesn't take the widget away from the other. `init` still runs on every\n * acquire: it is a no-op for the live config, and it remounts one that a\n * different config has since replaced.\n *\n * Holders of different configs contend for the one widget, and the latest to\n * acquire wins. When it lets go, the most recent remaining config is mounted\n * again, so no holder is left without a widget while it still wants one.\n */\nexport function acquireMount(key: string, init: (config: WidgetConfig) => () => void): () => void {\n const dispose = init(JSON.parse(key) as WidgetConfig)\n const count = (holders.get(key)?.count ?? 0) + 1\n // Re-inserted so the map's order is recency, which the release path reads.\n holders.delete(key)\n holders.set(key, { count, dispose })\n\n let isReleased = false\n return () => {\n if (isReleased) return\n isReleased = true\n const current = holders.get(key)\n if (!current) return\n current.count -= 1\n if (current.count > 0) return\n holders.delete(key)\n current.dispose()\n const survivor = [...holders.entries()].at(-1)\n if (!survivor) return\n // This runs inside some other component's cleanup; a failure to bring\n // the survivor back must not surface as that component's error.\n try {\n survivor[1].dispose = init(JSON.parse(survivor[0]) as WidgetConfig)\n } catch (error) {\n survivor[1].dispose = () => {}\n console.warn('[markup] could not remount the widget', error)\n }\n }\n}\n"],"mappings":";AAIA,IAAM,oBAAU,IAAI,IAAoB;AAYxC,SAAgB,EAAa,GAAa,GAAwD;CAChG,IAAM,IAAU,EAAK,KAAK,MAAM,CAAG,CAAiB,GAC9C,KAAS,EAAQ,IAAI,CAAG,CAAC,EAAE,SAAS,KAAK;CAG/C,AADA,EAAQ,OAAO,CAAG,GAClB,EAAQ,IAAI,GAAK;EAAE;EAAO;CAAQ,CAAC;CAEnC,IAAI,IAAa;CACjB,aAAa;EACX,IAAI,GAAY;EAChB,IAAa;EACb,IAAM,IAAU,EAAQ,IAAI,CAAG;EAG/B,IAFI,CAAC,MACL,IAAQ,OACJ,EAAQ,QAAQ,IAAG;EAEvB,AADA,EAAQ,OAAO,CAAG,GAClB,EAAQ,QAAQ;EAChB,IAAM,IAAW,CAAC,GAAG,EAAQ,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;EACxC,OAGL,IAAI;GACF,EAAS,EAAE,CAAC,UAAU,EAAK,KAAK,MAAM,EAAS,EAAE,CAAiB;EACpE,SAAS,GAAO;GAEd,AADA,EAAS,EAAE,CAAC,gBAAgB,CAAC,GAC7B,QAAQ,KAAK,yCAAyC,CAAK;EAC7D;CACF;AACF"}
|
package/dist/vue.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import { WidgetConfig } from './widget';
|
|
3
|
+
export type { WidgetConfig } from './widget';
|
|
4
|
+
export type UseMarkupOptions = WidgetConfig & {
|
|
5
|
+
/**
|
|
6
|
+
* `false` unmounts the widget, or never mounts it. Drive it from your build
|
|
7
|
+
* environment to keep the widget off production.
|
|
8
|
+
*
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Mounts the widget for as long as the calling component is mounted. Call it
|
|
15
|
+
* once from your root component's `setup`.
|
|
16
|
+
*
|
|
17
|
+
* Pass a plain object, a ref, or a getter. The widget remounts only when a
|
|
18
|
+
* value changes, not when the object is replaced by an equal one. Two
|
|
19
|
+
* components using the same options share one widget, and it stays until
|
|
20
|
+
* both unmount. Nothing mounts during server rendering, since mounting waits
|
|
21
|
+
* for `onMounted`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useMarkup(options: MaybeRefOrGetter<UseMarkupOptions>): void;
|
package/dist/vue.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { init as e, t } from "./widget.js";
|
|
2
|
+
import { t as n } from "./shared-mount-DABK4arh.js";
|
|
3
|
+
import { computed as r, onBeforeUnmount as i, onMounted as a, toValue as o, watch as s } from "vue";
|
|
4
|
+
//#region src/vue.ts
|
|
5
|
+
function c(c) {
|
|
6
|
+
let l = r(() => {
|
|
7
|
+
let { enabled: e = !0, ...n } = o(c);
|
|
8
|
+
return e ? t(n) : null;
|
|
9
|
+
}), u = null, d = (t) => {
|
|
10
|
+
u?.(), u = t === null ? null : n(t, e);
|
|
11
|
+
}, f = null;
|
|
12
|
+
a(() => {
|
|
13
|
+
d(l.value), f = s(l, d);
|
|
14
|
+
}), i(() => {
|
|
15
|
+
f?.(), d(null);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { c as useMarkup };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=vue.js.map
|
package/dist/vue.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue.js","names":[],"sources":["../src/vue.ts"],"sourcesContent":["import { computed, onBeforeUnmount, onMounted, toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nimport { configKey } from './runtime/config-key'\nimport { acquireMount } from './runtime/shared-mount'\nimport { init, type WidgetConfig } from './widget'\n\nexport type { WidgetConfig } from './widget'\n\nexport type UseMarkupOptions = WidgetConfig & {\n /**\n * `false` unmounts the widget, or never mounts it. Drive it from your build\n * environment to keep the widget off production.\n *\n * @default true\n */\n enabled?: boolean\n}\n\n/**\n * Mounts the widget for as long as the calling component is mounted. Call it\n * once from your root component's `setup`.\n *\n * Pass a plain object, a ref, or a getter. The widget remounts only when a\n * value changes, not when the object is replaced by an equal one. Two\n * components using the same options share one widget, and it stays until\n * both unmount. Nothing mounts during server rendering, since mounting waits\n * for `onMounted`.\n */\nexport function useMarkup(options: MaybeRefOrGetter<UseMarkupOptions>): void {\n const key = computed(() => {\n const { enabled = true, ...config } = toValue(options)\n return enabled ? configKey(config) : null\n })\n\n let release: (() => void) | null = null\n const apply = (next: string | null) => {\n release?.()\n release = next === null ? null : acquireMount(next, init)\n }\n\n let stopWatching: (() => void) | null = null\n onMounted(() => {\n apply(key.value)\n stopWatching = watch(key, apply)\n })\n onBeforeUnmount(() => {\n stopWatching?.()\n apply(null)\n })\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAU,GAAmD;CAC3E,IAAM,IAAM,QAAe;EACzB,IAAM,EAAE,aAAU,IAAM,GAAG,MAAW,EAAQ,CAAO;EACrD,OAAO,IAAU,EAAU,CAAM,IAAI;CACvC,CAAC,GAEG,IAA+B,MAC7B,KAAS,MAAwB;EAErC,AADA,IAAU,GACV,IAAU,MAAS,OAAO,OAAO,EAAa,GAAM,CAAI;CAC1D,GAEI,IAAoC;CAKxC,AAJA,QAAgB;EAEd,AADA,EAAM,EAAI,KAAK,GACf,IAAe,EAAM,GAAK,CAAK;CACjC,CAAC,GACD,QAAsB;EAEpB,AADA,IAAe,GACf,EAAM,IAAI;CACZ,CAAC;AACH"}
|