mesurer-solid 0.1.8 → 0.1.9-beta.1
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/AGENT_INTEGRATION.md +6 -5
- package/README.md +36 -7
- package/dist/agent.d.ts +3 -3
- package/dist/codex-plugin.d.ts +12 -6
- package/dist/context-plugin.d.ts +1 -1
- package/dist/context.d.ts +21 -6
- package/dist/core.d.ts +9 -8
- package/dist/core.js +22 -10
- package/dist/index.d.ts +38 -10
- package/dist/index.js +4012 -2687
- package/dist/inject-script.d.ts +3 -0
- package/dist/inject-script.js +300 -15
- package/dist/inject.d.ts +9 -1
- package/dist/inject.js +4010 -2678
- package/dist/layout-guides.d.ts +31 -0
- package/dist/plugins.d.ts +5 -2
- package/dist/plugins.js +2984 -1935
- package/dist/screenshot.d.ts +35 -2
- package/package.json +1 -1
- package/skills/mesurer-ui/SKILL.md +11 -5
package/AGENT_INTEGRATION.md
CHANGED
|
@@ -10,7 +10,6 @@ The normal agent workflow requires no Mesurer MCP server, localhost daemon, Send
|
|
|
10
10
|
npx --yes --package=mesurer-solid mesurer-skill install
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Use `mesurer-solid@beta` only when intentionally validating a prerelease.
|
|
14
13
|
|
|
15
14
|
The installer writes a self-contained skill and injection artifact:
|
|
16
15
|
|
|
@@ -124,13 +123,15 @@ Use the high-level Context and saved-intent methods for normal UI work. The lowe
|
|
|
124
123
|
| `distance(a, b)` | Measure two selector targets. |
|
|
125
124
|
| `viewport()` | Read viewport/document dimensions, scrolling, device pixel ratio, and overflow. |
|
|
126
125
|
| `feedback(selectors?)` | Read viewport data, inspected elements, plugin description, and plugin state together. |
|
|
127
|
-
| `command(id, args?)` | Execute a registered Mesurer command. |
|
|
126
|
+
| `command(id, args?)` | Execute a registered Mesurer command and return its JSON-safe result when present. |
|
|
128
127
|
| `state()` | Read plugin state. |
|
|
129
128
|
| `stable(frames?)` | Wait for fonts and rendering before measuring again. |
|
|
130
129
|
| `textEdits()` / `textEdit(id)` | Read saved direct-text and typography intent. |
|
|
131
130
|
|
|
132
131
|
Context adds `capabilities()`, `context()`, `contextText()`, `select()`, `annotations()`, `review()`, `capturePlan()`, `prepareCapture()`, and `finishCapture()`.
|
|
133
132
|
|
|
133
|
+
These inspection methods accept general DOM elements, including SVG. `select()` and point inspection can return SVG targets, and Context preserves their selector, tag, and geometry. Arrange and direct text editing remain HTML-only mutation paths.
|
|
134
|
+
|
|
134
135
|
Arrange adds `arrangements()`, `arrange()`, `showArrange()`, `arrangeCapturePlan()`, and `reviewArrange()`.
|
|
135
136
|
|
|
136
137
|
Use `capabilities().capabilities` before calling optional Context, Arrange, or text-edit paths. The complete public list is in [Capabilities](../../docs/CAPABILITIES.md).
|
|
@@ -148,7 +149,7 @@ const context = await window.__MESURER__.select([
|
|
|
148
149
|
|
|
149
150
|
Each selector must resolve to exactly one target. Missing or ambiguous selectors throw rather than binding to a guess.
|
|
150
151
|
|
|
151
|
-
For multi-selection, inspect every selected target and the relevant pair relationships. Prefer `selection.visualContext.distances`; use `distance(a, b)` when a needed pair has no existing evidence.
|
|
152
|
+
For multi-selection, inspect every selected target and the relevant pair relationships. Prefer `selection.visualContext.distances`; use `distance(a, b)` when a needed pair has no existing evidence. Box, guide, container, and diagonal semantics are defined in [Measurements and distance geometry](../../docs/MEASUREMENTS.md).
|
|
152
153
|
|
|
153
154
|
## Arrange intent
|
|
154
155
|
|
|
@@ -241,7 +242,7 @@ try {
|
|
|
241
242
|
}
|
|
242
243
|
```
|
|
243
244
|
|
|
244
|
-
The optional human `screenshot()` plugin from `mesurer-solid/plugins` is a separate camera workflow. It
|
|
245
|
+
The optional human `screenshot()` plugin from `mesurer-solid/plugins` is a separate camera workflow. It may use application-native, Chromium extension, or browser display capture internally, but none of those paths changes the agent contract above. Do not add or configure a host capture path only to collect coding-agent evidence. Preserve an existing human preview unless the task is specifically about Screenshot behavior.
|
|
245
246
|
|
|
246
247
|
## Optional human-to-Codex delivery
|
|
247
248
|
|
|
@@ -253,7 +254,7 @@ Delivery uses Codex's native durable queue. Mesurer queues once and keeps the qu
|
|
|
253
254
|
|
|
254
255
|
The browser plugin connects lazily on the first Queue to Codex or thread-picker action. Page affinity and an explicit destination override persist per tab. If several registered threads are visible and the page has no saved destination, the user must choose one.
|
|
255
256
|
|
|
256
|
-
The typed `codex:v1` service exposes `health()`, `listThreads()`, `useThread(thread)`, `delivery(deliveryId)`, and `send(
|
|
257
|
+
The typed `codex:v1` service exposes `health()`, `listThreads()`, `useThread(thread)`, `delivery(deliveryId)`, and canonical `queue(request?)`. `send(request?)` remains a compatibility alias. The generic plugin command is `codex.queue`; `codex.send` remains its compatibility alias. Queue submission is single-flight. A matched completed turn may remove only the annotation ids sent with that delivery; interrupted, failed, ambiguous, or unreadable work keeps them.
|
|
257
258
|
|
|
258
259
|
Mesurer does not create new Codex threads. Create or open the thread in Codex and let `SessionStart` register it. Turn completion is transport lifecycle, not proof that the requested UI result is correct.
|
|
259
260
|
|
package/README.md
CHANGED
|
@@ -20,7 +20,6 @@ or:
|
|
|
20
20
|
npm install -D mesurer-solid
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Use `mesurer-solid@beta` only when intentionally testing a prerelease.
|
|
24
23
|
|
|
25
24
|
## Usage
|
|
26
25
|
|
|
@@ -38,10 +37,12 @@ if (import.meta.env.DEV) {
|
|
|
38
37
|
}
|
|
39
38
|
```
|
|
40
39
|
|
|
41
|
-
For Vite, put this in the existing browser entry such as `src/main.tsx`, `src/main.ts`, or `src/index.tsx`. In Electron, use the renderer entry. In SSR applications, mount from a client-only module or lifecycle.
|
|
40
|
+
For Vite, put this in the existing browser entry such as `src/main.tsx`, `src/main.ts`, or `src/index.tsx`. In Electron, use the renderer entry and keep privileged Electron work in preload/main. If preload exposes `window.__MESURER_HOST__.captureScreenshot`, Screenshot uses native capture automatically. Renderer configuration remains `screenshot()`; there is no Electron-specific Screenshot factory or provider option. In SSR applications, mount from a client-only module or lifecycle.
|
|
42
41
|
|
|
43
42
|
`src/dev/mesurer.ts` is an optional organization pattern, not a required filename or directory. Do not mount Mesurer from `vite.config.ts`, server/API code, Node-only scripts, an Electron main process, or a module that also executes during SSR.
|
|
44
43
|
|
|
44
|
+
The returned handle owns the mount. Await `mesurer.ready` when startup completion, initial rendered stability, or direct host access matters, call `mesurer.dispose()` for explicit cleanup, or pass `signal` when an existing lifecycle should own disposal.
|
|
45
|
+
|
|
45
46
|
Full placement examples: [Getting started](https://github.com/jhomra21/mesurer-solid/blob/main/docs/GETTING_STARTED.md).
|
|
46
47
|
|
|
47
48
|
## First-party plugins
|
|
@@ -50,13 +51,14 @@ All public first-party plugin factories are exported from `mesurer-solid/plugins
|
|
|
50
51
|
|
|
51
52
|
```ts
|
|
52
53
|
import { mountMesurer } from "mesurer-solid"
|
|
53
|
-
import { arrange, context, screenshot } from "mesurer-solid/plugins"
|
|
54
|
+
import { arrange, context, layoutGuides, screenshot } from "mesurer-solid/plugins"
|
|
54
55
|
|
|
55
56
|
const mesurer = mountMesurer({
|
|
56
57
|
agent: true,
|
|
57
58
|
plugins: [
|
|
58
59
|
context(),
|
|
59
60
|
arrange(),
|
|
61
|
+
layoutGuides(),
|
|
60
62
|
screenshot(),
|
|
61
63
|
],
|
|
62
64
|
})
|
|
@@ -64,7 +66,11 @@ const mesurer = mountMesurer({
|
|
|
64
66
|
|
|
65
67
|
The base inspector includes Select, X-ray, Rulers, Typography, Guides, Distance, Settings, plugin hosting, direct text editing, and the low-level inspection API. Native Color Picker is available only when the host exposes an operational `EyeDropper`.
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
`mesurer-solid/plugins` also exports the built-in factories for lower-level composition. Normal mounts already include the built-ins. Use `excludeBuiltins` with names such as `"xray"`, `"typography"`, and `"colorPicker"` when a mount should omit one.
|
|
70
|
+
|
|
71
|
+
Resolve plugin-owned capabilities with `await mesurer.service<T>(serviceId)`. The helper waits for configured plugins to finish loading and keeps normal consumers on the mounted interface instead of requiring `pluginHost.service.get(...)`. Falsy registered values are returned unchanged.
|
|
72
|
+
|
|
73
|
+
Advanced integrations may supply their own `pluginHost`. That host remains caller-owned; disposing or aborting the Mesurer mount does not dispose it. Use `onPluginHost` only when code needs the host before startup settles.
|
|
68
74
|
|
|
69
75
|
| Entry | Purpose |
|
|
70
76
|
| --- | --- |
|
|
@@ -77,27 +83,47 @@ For explicit plugin composition, `mesurer-solid/plugins` also exports `select`,
|
|
|
77
83
|
| `mesurer-codex` | Run the optional loopback Codex queue companion |
|
|
78
84
|
| `mesurer-codex-connect` | Start or reuse the matching Codex companion and register the current Codex session |
|
|
79
85
|
|
|
86
|
+
Programmatic injection reuses an existing connected instance by default. Lifecycle-owning integrations can set `recoverDisconnected: true` in `MesurerInjectConfig` to remount Mesurer when page DOM replacement disconnects its host. The option defaults to `false`, so ordinary one-shot injection does not silently reappear after disposal.
|
|
87
|
+
|
|
80
88
|
## Features
|
|
81
89
|
|
|
82
|
-
- Select one or many rendered elements and inspect exact geometry.
|
|
90
|
+
- Select one or many rendered HTML or SVG elements and inspect exact geometry.
|
|
83
91
|
- Measure distance and pairwise multi-selection spacing.
|
|
84
92
|
- Use X-ray, guides, rulers, and persisted settings.
|
|
93
|
+
- Add page-scoped columns, rows, or pixel grids with the optional `layoutGuides()` plugin. Guide edits participate in plugin undo/redo, and Context includes the current page's saved guides with their visibility state.
|
|
85
94
|
- Inspect Typography and preview reversible direct copy/style changes.
|
|
86
95
|
- Arrange selected UI into a Desired position without changing source.
|
|
87
|
-
- Capture
|
|
96
|
+
- Capture page regions through the optional Screenshot plugin. It selects native host capture, the Chromium extension adapter, or browser display capture internally.
|
|
88
97
|
- Read selection, measurements, guides, annotations, layout, styles, and saved human intent through Context and agent APIs.
|
|
89
98
|
- Keep saved annotations across same-tab reloads and conservatively rebind them to their original DOM targets; markers, cards, and ownership evidence stay attached through scrolling, repeated-note markers stay local, Add Note remains available while a note is open, and cards/composers occlude Select hover and selection chrome.
|
|
90
99
|
- Extend the runtime with tools, settings, overlays, commands, hooks, state, and services.
|
|
91
100
|
- Compact the toolbar to active controls without changing tool state or order.
|
|
101
|
+
- Choose System, Light, or Dark appearance while keeping the same theme across isolated and document-backed Mesurer UI.
|
|
92
102
|
|
|
93
103
|
Arrange is not a toolbar mode. It can be activated before a selection exists and enables Select automatically. Turning Arrange off leaves Select active; turning Select off exits Arrange.
|
|
94
104
|
|
|
105
|
+
Toolbar dragging starts after the pointer crosses the drag threshold. Dragging from Settings, Guide, or plugin triggers closes the open menu or panel. Pointer activity inside menus, dialogs, form controls, editable regions, and sliders does not drag the toolbar.
|
|
106
|
+
|
|
107
|
+
Select and agent point inspection use the same rendered hit-test path. They can target SVG and visible `pointer-events:none` descendants instead of collapsing those descendants to an interactive ancestor. Open shadow roots are traversed; closed shadow roots remain browser-owned boundaries. Context and annotations accept the same SVG targets. Arrange and direct text editing only mutate HTML elements.
|
|
108
|
+
|
|
109
|
+
Persisted workspace evidence is page-scoped by route, including sorted query parameters. In-tab navigation swaps the current page workspace without carrying page-owned guides or selection state to another route. Toolbar placement remains tab-session UI and survives those route changes and reloads.
|
|
110
|
+
|
|
95
111
|
Direct text editing respects native editing boundaries. Descendants of an editable ancestor remain native, while a nested `contenteditable="false"` boundary ends inherited editability and can become a Mesurer target when the normal direct-text rules pass. Mixed inline copy can target the exact direct text run before or after an inline child without flattening or recreating that child, and the host element keeps its native DOM APIs throughout the interaction.
|
|
96
112
|
|
|
97
113
|
While direct text editing is active, Mesurer keeps one visible edit ring, keeps the selected dimensions pill and Typography separated by the same `2px` rendered gap when the card is below the source, and keeps Typography stationary during ordinary pointer movement. The selection-adjacent Add Note button is suppressed only for the active edit and returns when the editor closes; saved annotation markers and panels remain available.
|
|
98
114
|
|
|
99
115
|
Mesurer previews text, styles, and Arrange transforms only while it still owns the value it applied. Host-authored changes take ownership and are preserved through undo/redo, Live review, cleanup, and disposal.
|
|
100
116
|
|
|
117
|
+
## Appearance
|
|
118
|
+
|
|
119
|
+
The default appearance is `"system"`. Users can change it under **Settings > General > Appearance**, or applications can choose the initial mode:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
mountMesurer({ theme: "light" })
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The setting accepts `"system"`, `"light"`, or `"dark"` and persists with the other Mesurer settings. System mode follows `prefers-color-scheme`.
|
|
126
|
+
|
|
101
127
|
## Shortcuts
|
|
102
128
|
|
|
103
129
|
Global shortcuts are enabled by default. Turn them off from **Settings > General > Shortcuts** or pass `shortcutsEnabled: false` to `mountMesurer()`. Toolbar controls, editor-local keys, and Escape/cancel behavior remain available.
|
|
@@ -111,6 +137,7 @@ Global shortcuts are enabled by default. Turn them off from **Settings > General
|
|
|
111
137
|
| `R` | Rulers |
|
|
112
138
|
| `A` | Typography |
|
|
113
139
|
| `G` | Guides |
|
|
140
|
+
| `L` | Layout Guides when the plugin is enabled |
|
|
114
141
|
| `H` / `V` | Horizontal / vertical guide orientation |
|
|
115
142
|
| `Alt` / `Option` | Distance overlay |
|
|
116
143
|
| `Cmd/Ctrl + ,` | Settings |
|
|
@@ -170,8 +197,10 @@ See [Queue Context feedback to Codex](https://github.com/jhomra21/mesurer-solid/
|
|
|
170
197
|
- [Capabilities](https://github.com/jhomra21/mesurer-solid/blob/main/docs/CAPABILITIES.md)
|
|
171
198
|
- [Getting started](https://github.com/jhomra21/mesurer-solid/blob/main/docs/GETTING_STARTED.md)
|
|
172
199
|
- [Direct text editing and Typography](https://github.com/jhomra21/mesurer-solid/blob/main/docs/TEXT_EDITING.md)
|
|
173
|
-
- [Arrange](https://github.com/jhomra21/mesurer-solid/blob/main/docs/ARRANGE.md)
|
|
200
|
+
- [Arrange](https://github.com/jhomra21/mesurer-solid/blob/main/docs/ARRANGE.md) and [Layout Guides](https://github.com/jhomra21/mesurer-solid/blob/main/docs/LAYOUT_GUIDES.md)
|
|
201
|
+
- [Measurements and distance geometry](https://github.com/jhomra21/mesurer-solid/blob/main/docs/MEASUREMENTS.md)
|
|
174
202
|
- [Screenshots](https://github.com/jhomra21/mesurer-solid/blob/main/docs/SCREENSHOTS.md)
|
|
203
|
+
- [Electron renderer example](https://github.com/jhomra21/mesurer-solid/blob/main/examples/electron-renderer/README.md)
|
|
175
204
|
- [Context workflow](https://github.com/jhomra21/mesurer-solid/blob/main/docs/CONTEXT_WORKFLOW.md)
|
|
176
205
|
- [Queue Context feedback to Codex](https://github.com/jhomra21/mesurer-solid/blob/main/docs/CODEX.md)
|
|
177
206
|
- [Browser and agent integration](https://github.com/jhomra21/mesurer-solid/blob/main/docs/BROWSER_HARNESS.md)
|
package/dist/agent.d.ts
CHANGED
|
@@ -110,20 +110,20 @@ export type AgentViewportSnapshot = {
|
|
|
110
110
|
export type AgentFeedbackSnapshot = {
|
|
111
111
|
viewport: AgentViewportSnapshot;
|
|
112
112
|
elements: AgentElementInspection[];
|
|
113
|
-
plugins: MesurerPluginDescription
|
|
113
|
+
plugins: MesurerPluginDescription;
|
|
114
114
|
pluginState: PluginStateSnapshot;
|
|
115
115
|
};
|
|
116
116
|
type AgentCommandArgs = Parameters<MesurerPluginHost["command"]["execute"]>[1];
|
|
117
117
|
export type MesurerAgentHarness = {
|
|
118
118
|
ready(): Promise<void>;
|
|
119
|
-
describe(): Promise<MesurerPluginDescription
|
|
119
|
+
describe(): Promise<MesurerPluginDescription>;
|
|
120
120
|
inspect(selector: string, index?: number): AgentElementInspection | null;
|
|
121
121
|
inspectAll(selector: string, limit?: number): AgentElementInspection[];
|
|
122
122
|
at(x: number, y: number): AgentElementInspection | null;
|
|
123
123
|
distance(a: string, b: string): AgentDistance | null;
|
|
124
124
|
viewport(): AgentViewportSnapshot;
|
|
125
125
|
feedback(selectors?: string[]): Promise<AgentFeedbackSnapshot>;
|
|
126
|
-
command(id: string, args?: AgentCommandArgs):
|
|
126
|
+
command(id: string, args?: AgentCommandArgs): ReturnType<MesurerPluginHost["command"]["execute"]>;
|
|
127
127
|
state(): Promise<PluginStateSnapshot>;
|
|
128
128
|
textEdits(): Promise<MesurerTextEditIntent[]>;
|
|
129
129
|
textEdit(id: string): Promise<MesurerTextEditIntent>;
|
package/dist/codex-plugin.d.ts
CHANGED
|
@@ -11,14 +11,16 @@ export type MesurerCodexPluginOptions = {
|
|
|
11
11
|
/** Remove annotations included in a delivery after Codex reports that turn finished. Defaults to true. */
|
|
12
12
|
clearCompletedAnnotations?: boolean;
|
|
13
13
|
};
|
|
14
|
-
export type
|
|
15
|
-
/** Optional instruction for this
|
|
14
|
+
export type MesurerCodexQueueRequest = {
|
|
15
|
+
/** Optional instruction for this queue operation. */
|
|
16
16
|
instruction?: string;
|
|
17
|
-
/**
|
|
17
|
+
/** Queue only these saved annotation ids. When omitted, all saved annotations are queued. */
|
|
18
18
|
annotationIds?: string[];
|
|
19
|
-
/**
|
|
19
|
+
/** Queue to a particular bridge-visible Codex thread for this request. */
|
|
20
20
|
thread?: string;
|
|
21
21
|
};
|
|
22
|
+
/** @deprecated Use `MesurerCodexQueueRequest`. */
|
|
23
|
+
export type MesurerCodexSendRequest = MesurerCodexQueueRequest;
|
|
22
24
|
export type MesurerCodexDeliveryStatus = "queued" | "working" | "completed" | "interrupted";
|
|
23
25
|
export type MesurerCodexDispatchStatus = "persisting" | "persisted" | "resumed" | "already-loaded" | "unsupported" | "wake-failed" | "untracked" | "desktop-local" | "waiting-active" | "desktop-sent" | "desktop-opened" | "desktop-send-uncertain" | "desktop-wait-failed";
|
|
24
26
|
export type MesurerCodexDelivery = {
|
|
@@ -35,7 +37,7 @@ export type MesurerCodexDelivery = {
|
|
|
35
37
|
createdAt: number;
|
|
36
38
|
updatedAt: number;
|
|
37
39
|
};
|
|
38
|
-
export type
|
|
40
|
+
export type MesurerCodexQueueResult = {
|
|
39
41
|
thread: string;
|
|
40
42
|
output: string;
|
|
41
43
|
/** Mesurer currently delivers feedback as a queued Codex follow-up, never as an in-flight steer. */
|
|
@@ -52,6 +54,8 @@ export type MesurerCodexSendResult = {
|
|
|
52
54
|
/** Exact saved annotations included in this queued request. */
|
|
53
55
|
annotationIds: string[];
|
|
54
56
|
};
|
|
57
|
+
/** @deprecated Use `MesurerCodexQueueResult`. */
|
|
58
|
+
export type MesurerCodexSendResult = MesurerCodexQueueResult;
|
|
55
59
|
export type MesurerCodexHealth = {
|
|
56
60
|
/** Current bridge default target. Null when the bridge has not been bound yet. */
|
|
57
61
|
thread: string | null;
|
|
@@ -91,6 +95,8 @@ export type MesurerCodexService = {
|
|
|
91
95
|
* Queue Context for the page-pinned/default target or one explicit bridge-visible thread.
|
|
92
96
|
* This does not steer or interrupt an in-flight Codex turn.
|
|
93
97
|
*/
|
|
94
|
-
|
|
98
|
+
queue(request?: MesurerCodexQueueRequest): Promise<MesurerCodexQueueResult>;
|
|
99
|
+
/** @deprecated Use `queue()`; Mesurer delivery is durable queueing, not in-flight send/steer. */
|
|
100
|
+
send(request?: MesurerCodexQueueRequest): Promise<MesurerCodexQueueResult>;
|
|
95
101
|
};
|
|
96
102
|
export declare function codex(options?: MesurerCodexPluginOptions): MesurerPlugin;
|
package/dist/context-plugin.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type MesurerContextService = {
|
|
|
11
11
|
context(request?: MesurerContextRequest): Promise<MesurerContextV1>;
|
|
12
12
|
contextText(request?: MesurerContextRequest): Promise<string>;
|
|
13
13
|
copyContext(request?: MesurerContextRequest): Promise<void>;
|
|
14
|
-
select(selectors: string | string[]): Promise<MesurerContextV1>;
|
|
14
|
+
select(selectors: string | readonly string[]): Promise<MesurerContextV1>;
|
|
15
15
|
annotations(): Promise<MesurerAnnotation[]>;
|
|
16
16
|
/** Remove one saved annotation after a trusted workflow has completed it. */
|
|
17
17
|
removeAnnotation(annotationId: string): Promise<void>;
|
package/dist/context.d.ts
CHANGED
|
@@ -147,6 +147,18 @@ export type MesurerContextGuide = {
|
|
|
147
147
|
orientation: "vertical" | "horizontal";
|
|
148
148
|
position: number;
|
|
149
149
|
};
|
|
150
|
+
export type MesurerContextLayoutGuide = {
|
|
151
|
+
id: string;
|
|
152
|
+
kind: "columns" | "rows" | "grid";
|
|
153
|
+
visible: boolean;
|
|
154
|
+
color: string;
|
|
155
|
+
opacity: number;
|
|
156
|
+
count: number;
|
|
157
|
+
size: number;
|
|
158
|
+
gutter: number;
|
|
159
|
+
offset: number;
|
|
160
|
+
align: "stretch" | "min" | "center" | "max";
|
|
161
|
+
};
|
|
150
162
|
export type MesurerContextMeasurement = {
|
|
151
163
|
id: string;
|
|
152
164
|
rect: MesurerContextRect;
|
|
@@ -209,6 +221,7 @@ export type MesurerContextV1 = {
|
|
|
209
221
|
targets: MesurerContextTarget[];
|
|
210
222
|
visualContext: {
|
|
211
223
|
guides: MesurerContextGuide[];
|
|
224
|
+
layoutGuides: MesurerContextLayoutGuide[];
|
|
212
225
|
measurements: MesurerContextMeasurement[];
|
|
213
226
|
distances: MesurerContextDistance[];
|
|
214
227
|
};
|
|
@@ -266,7 +279,7 @@ export type MesurerWorkspaceContextSource = {
|
|
|
266
279
|
deltaX: number;
|
|
267
280
|
deltaY: number;
|
|
268
281
|
snapped?: boolean;
|
|
269
|
-
elementRef?:
|
|
282
|
+
elementRef?: Element | null;
|
|
270
283
|
}>;
|
|
271
284
|
activeMeasurement: {
|
|
272
285
|
id: string;
|
|
@@ -274,14 +287,14 @@ export type MesurerWorkspaceContextSource = {
|
|
|
274
287
|
deltaX: number;
|
|
275
288
|
deltaY: number;
|
|
276
289
|
snapped?: boolean;
|
|
277
|
-
elementRef?:
|
|
290
|
+
elementRef?: Element | null;
|
|
278
291
|
} | null;
|
|
279
292
|
heldDistances: Array<{
|
|
280
293
|
id: string;
|
|
281
294
|
rectA: MesurerContextRect;
|
|
282
295
|
rectB: MesurerContextRect;
|
|
283
|
-
elementRefA?:
|
|
284
|
-
elementRefB?:
|
|
296
|
+
elementRefA?: Element | null;
|
|
297
|
+
elementRefB?: Element | null;
|
|
285
298
|
horizontal: {
|
|
286
299
|
x1: number;
|
|
287
300
|
x2: number;
|
|
@@ -302,14 +315,14 @@ export type MesurerWorkspaceContextSource = {
|
|
|
302
315
|
}>;
|
|
303
316
|
} | null;
|
|
304
317
|
currentSelection(): {
|
|
305
|
-
elements:
|
|
318
|
+
elements: Element[];
|
|
306
319
|
region: MesurerContextRect | null;
|
|
307
320
|
};
|
|
308
321
|
annotations(): MesurerAnnotation[];
|
|
309
322
|
annotation(id: string): (MesurerAnnotation & {
|
|
310
323
|
resolvedTargets: Array<{
|
|
311
324
|
target: MesurerAnnotationTarget;
|
|
312
|
-
element:
|
|
325
|
+
element: Element | null;
|
|
313
326
|
}>;
|
|
314
327
|
}) | null;
|
|
315
328
|
annotationRect(id: string): MesurerContextRect | null;
|
|
@@ -319,6 +332,7 @@ export declare function captureMesurerContext(options: {
|
|
|
319
332
|
ownerDocument: Document;
|
|
320
333
|
ownerWindow: Window;
|
|
321
334
|
request?: MesurerContextRequest;
|
|
335
|
+
layoutGuides?: MesurerContextLayoutGuide[];
|
|
322
336
|
}): MesurerContextV1;
|
|
323
337
|
export declare function formatMesurerContext(context: MesurerContextV1): string;
|
|
324
338
|
export declare function createMesurerCapturePlan(context: MesurerContextV1): MesurerCapturePlanV1;
|
|
@@ -327,5 +341,6 @@ export declare function reviewMesurerAnnotation(options: {
|
|
|
327
341
|
ownerDocument: Document;
|
|
328
342
|
ownerWindow: Window;
|
|
329
343
|
annotationId: string;
|
|
344
|
+
layoutGuides?: MesurerContextLayoutGuide[];
|
|
330
345
|
}): MesurerReviewV1;
|
|
331
346
|
export declare function copyTextToClipboard(ownerDocument: Document, ownerWindow: Window, text: string): Promise<void>;
|
package/dist/core.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export type OverlayContribution = {
|
|
|
77
77
|
};
|
|
78
78
|
export type CommandHandler = (args: PluginValue | undefined, context: {
|
|
79
79
|
source?: PluginValue;
|
|
80
|
-
}) => void | Promise<void>;
|
|
80
|
+
}) => void | PluginValue | Promise<void | PluginValue>;
|
|
81
81
|
export type HookHandler = (event: PluginValue) => void | Promise<void>;
|
|
82
82
|
export type StateSliceDefinition<T extends PluginValue = PluginValue> = {
|
|
83
83
|
id: string;
|
|
@@ -103,7 +103,7 @@ export type MesurerPluginContext = {
|
|
|
103
103
|
};
|
|
104
104
|
command: {
|
|
105
105
|
register(id: string, handler: CommandHandler): Registration;
|
|
106
|
-
execute(id: string, args?: PluginValue, source?: PluginValue): Promise<
|
|
106
|
+
execute(id: string, args?: PluginValue, source?: PluginValue): Promise<PluginValue | undefined>;
|
|
107
107
|
};
|
|
108
108
|
hook: {
|
|
109
109
|
on(name: string, handler: HookHandler): Registration;
|
|
@@ -120,8 +120,8 @@ export type MesurerPluginContext = {
|
|
|
120
120
|
export type MesurerPlugin = {
|
|
121
121
|
id: PluginId;
|
|
122
122
|
version?: string;
|
|
123
|
-
requires?: string[];
|
|
124
|
-
provides?: string[];
|
|
123
|
+
requires?: readonly string[];
|
|
124
|
+
provides?: readonly string[];
|
|
125
125
|
setup(context: MesurerPluginContext): void | Promise<void>;
|
|
126
126
|
};
|
|
127
127
|
export type MesurerPluginDescription = {
|
|
@@ -175,7 +175,7 @@ export type MesurerPluginHost = {
|
|
|
175
175
|
get<T>(id: string): T | undefined;
|
|
176
176
|
};
|
|
177
177
|
command: {
|
|
178
|
-
execute(id: string, args?: PluginValue, source?: PluginValue): Promise<
|
|
178
|
+
execute(id: string, args?: PluginValue, source?: PluginValue): Promise<PluginValue | undefined>;
|
|
179
179
|
};
|
|
180
180
|
hook: {
|
|
181
181
|
emit(name: string, event: PluginValue): Promise<void>;
|
|
@@ -190,6 +190,7 @@ export type MesurerPluginHost = {
|
|
|
190
190
|
};
|
|
191
191
|
export declare const defineMesurerPlugin: <T extends MesurerPlugin>(plugin: T) => T;
|
|
192
192
|
export declare function createMesurerPluginHost(): MesurerPluginHost;
|
|
193
|
-
export
|
|
194
|
-
plugins?: MesurerPlugin[];
|
|
195
|
-
}
|
|
193
|
+
export type MesurerRuntimeOptions = {
|
|
194
|
+
plugins?: readonly MesurerPlugin[];
|
|
195
|
+
};
|
|
196
|
+
export declare function createMesurerRuntime(options?: MesurerRuntimeOptions): Promise<MesurerPluginHost>;
|
package/dist/core.js
CHANGED
|
@@ -85,8 +85,10 @@ function i() {
|
|
|
85
85
|
if (!o) throw Error(`Unknown Mesurer command: ${e}`);
|
|
86
86
|
let s = t === 0, c = s ? x("history") : null;
|
|
87
87
|
t += 1;
|
|
88
|
+
let l;
|
|
88
89
|
try {
|
|
89
|
-
await o.handler(n, { source: a })
|
|
90
|
+
let t = await o.handler(n, { source: a });
|
|
91
|
+
t !== void 0 && (l = t), await i.emit("command", {
|
|
90
92
|
id: e,
|
|
91
93
|
args: n
|
|
92
94
|
});
|
|
@@ -97,6 +99,7 @@ function i() {
|
|
|
97
99
|
let e = x("history");
|
|
98
100
|
C(c, e) || (h.push(c), h.length > r && h.shift(), g.length = 0);
|
|
99
101
|
}
|
|
102
|
+
return l;
|
|
100
103
|
}, E = () => {
|
|
101
104
|
let e = h.pop();
|
|
102
105
|
return e ? (g.push(x("history")), g.length > r && g.shift(), S(e, "history"), _(void 0, "history"), !0) : !1;
|
|
@@ -223,8 +226,8 @@ function i() {
|
|
|
223
226
|
plugins: [...a.values()].map(({ plugin: e }) => ({
|
|
224
227
|
id: e.id,
|
|
225
228
|
version: e.version,
|
|
226
|
-
requires: e.requires ?? [],
|
|
227
|
-
provides: e.provides ?? []
|
|
229
|
+
requires: [...e.requires ?? []],
|
|
230
|
+
provides: [...e.provides ?? []]
|
|
228
231
|
})),
|
|
229
232
|
tools: z.tools().map(({ active: e, disabled: t, hidden: n, icon: r, menu: i, ...a }) => a),
|
|
230
233
|
settings: z.settings().map(({ controls: e = [], ...t }) => ({
|
|
@@ -258,15 +261,24 @@ function i() {
|
|
|
258
261
|
return z;
|
|
259
262
|
}
|
|
260
263
|
//#endregion
|
|
264
|
+
//#region ../mesurer-core/dist/runtime.js
|
|
265
|
+
async function a(e = {}) {
|
|
266
|
+
let t = i();
|
|
267
|
+
try {
|
|
268
|
+
for (let n of e.plugins ?? []) await t.load(n);
|
|
269
|
+
return t;
|
|
270
|
+
} catch (e) {
|
|
271
|
+
throw t.dispose(), e;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
261
275
|
//#region src/core.ts
|
|
262
|
-
var
|
|
263
|
-
function
|
|
276
|
+
var o = (e) => e;
|
|
277
|
+
function s() {
|
|
264
278
|
return i();
|
|
265
279
|
}
|
|
266
|
-
async function
|
|
267
|
-
|
|
268
|
-
for (let n of e.plugins ?? []) await t.load(n);
|
|
269
|
-
return t;
|
|
280
|
+
async function c(e = {}) {
|
|
281
|
+
return a(e);
|
|
270
282
|
}
|
|
271
283
|
//#endregion
|
|
272
|
-
export {
|
|
284
|
+
export { s as createMesurerPluginHost, c as createMesurerRuntime, o as defineMesurerPlugin };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { type MesurerAgentHarness, type MesurerTextEditIntent } from "./agent";
|
|
2
|
-
import type
|
|
2
|
+
import { type ArrangeCapturePlan, type ArrangeIntent, type ArrangePresentation, type ArrangeReview } from "./arrange";
|
|
3
3
|
import type { MesurerAnnotation, MesurerCapturePlanV1, MesurerContextRequest, MesurerContextV1, MesurerReviewV1 } from "./context";
|
|
4
4
|
import type { MesurerPlugin, MesurerPluginDescription, MesurerPluginHost } from "./core";
|
|
5
5
|
import { type MesurerHostLayerMode } from "./host-layer";
|
|
6
6
|
export type ColorPickerFormat = "hex" | "rgb" | "hsl" | "oklch";
|
|
7
|
+
export type MesurerTheme = "system" | "light" | "dark";
|
|
8
|
+
/** Public built-in names, aligned with the factories exported by `mesurer-solid/plugins`. */
|
|
9
|
+
export type MesurerBuiltin = "select" | "xray" | "colorPicker" | "rulers" | "typography" | "guides" | "distance" | "settings";
|
|
10
|
+
/** @deprecated Internal compatibility ids used by the older `excludePlugins` option. */
|
|
7
11
|
export type MesurerBuiltinPluginId = "select" | "xray" | "color-picker" | "rulers" | "text-inspector" | "guides" | "distance" | "settings";
|
|
8
12
|
export type LinePattern = "solid" | "dashed" | "dotted";
|
|
9
13
|
export type LineStyle = {
|
|
@@ -80,6 +84,7 @@ export type MesurerStoredSettings = {
|
|
|
80
84
|
multiMeasureEnabled?: boolean;
|
|
81
85
|
persistOnReload?: boolean;
|
|
82
86
|
shortcutsEnabled?: boolean;
|
|
87
|
+
theme?: MesurerTheme;
|
|
83
88
|
guideStyle?: Partial<GuideStyle>;
|
|
84
89
|
selectionSpacingStyle?: Partial<SelectionSpacingStyle>;
|
|
85
90
|
rulerSettings?: Partial<RulerSettings>;
|
|
@@ -106,6 +111,7 @@ export type MesurerPersistence = {
|
|
|
106
111
|
saveWorkspace(workspace: MesurerStoredWorkspace): void;
|
|
107
112
|
clearWorkspace(): void;
|
|
108
113
|
clearSettings(): void;
|
|
114
|
+
setPageKey?(pageKey: string): void;
|
|
109
115
|
subscribe?: (listener: (snapshot: MesurerPersistenceSnapshot | null, source?: {
|
|
110
116
|
settings?: boolean;
|
|
111
117
|
workspace?: boolean;
|
|
@@ -122,6 +128,7 @@ export type MesurerOptions = {
|
|
|
122
128
|
hoverHighlightEnabled?: boolean;
|
|
123
129
|
persistOnReload?: boolean;
|
|
124
130
|
shortcutsEnabled?: boolean;
|
|
131
|
+
theme?: MesurerTheme;
|
|
125
132
|
persistKey?: string;
|
|
126
133
|
persistence?: MesurerPersistence;
|
|
127
134
|
onPersistenceError?: (cause: unknown) => void;
|
|
@@ -139,10 +146,19 @@ export type MesurerOptions = {
|
|
|
139
146
|
* Omitted first-party plugins remain toggleable in Settings from the same canonical
|
|
140
147
|
* registry; callers never maintain a separate availability or Settings list.
|
|
141
148
|
*/
|
|
142
|
-
plugins?: MesurerPlugin[];
|
|
143
|
-
|
|
149
|
+
plugins?: readonly MesurerPlugin[];
|
|
150
|
+
/** Built-in tools to omit from this mount. Names match the public plugin factories. */
|
|
151
|
+
excludeBuiltins?: readonly MesurerBuiltin[];
|
|
152
|
+
/** @deprecated Use `excludeBuiltins`. This compatibility option uses internal built-in ids. */
|
|
153
|
+
excludePlugins?: readonly MesurerBuiltinPluginId[];
|
|
154
|
+
/**
|
|
155
|
+
* Advanced: supply a plugin host owned outside this mount.
|
|
156
|
+
* The caller remains responsible for disposing the supplied host.
|
|
157
|
+
*/
|
|
144
158
|
pluginHost?: MesurerPluginHost;
|
|
159
|
+
/** Advanced: receive the live host before configured plugin setup settles. */
|
|
145
160
|
onPluginHost?: (host: MesurerPluginHost) => void;
|
|
161
|
+
/** @deprecated Await `mounted.ready` instead. */
|
|
146
162
|
onPluginsReady?: (host: MesurerPluginHost) => void;
|
|
147
163
|
onPluginError?: (cause: unknown, pluginId: string) => void;
|
|
148
164
|
};
|
|
@@ -151,7 +167,16 @@ export type MountMesurerOptions = MesurerOptions & {
|
|
|
151
167
|
isolate?: boolean;
|
|
152
168
|
shadowMode?: ShadowRootMode;
|
|
153
169
|
topLayer?: boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Expose the browser agent API on the owning Window. The mounted handle always
|
|
172
|
+
* exposes `agent`; this option controls only the global bridge.
|
|
173
|
+
*/
|
|
154
174
|
agent?: boolean | AgentBridgeOptions;
|
|
175
|
+
/**
|
|
176
|
+
* Dispose this mount when the signal aborts.
|
|
177
|
+
* A caller-supplied pluginHost keeps its separate lifecycle.
|
|
178
|
+
*/
|
|
179
|
+
signal?: AbortSignal;
|
|
155
180
|
};
|
|
156
181
|
export type MesurerAgentCapabilities = {
|
|
157
182
|
protocol: "mesurer.agent/v1";
|
|
@@ -170,7 +195,7 @@ export type MesurerContextHarness = {
|
|
|
170
195
|
capabilities(): MesurerAgentCapabilities;
|
|
171
196
|
context(request?: MesurerContextRequest): Promise<MesurerContextV1>;
|
|
172
197
|
contextText(request?: MesurerContextRequest): Promise<string>;
|
|
173
|
-
select(selectors: string | string[]): Promise<MesurerContextV1>;
|
|
198
|
+
select(selectors: string | readonly string[]): Promise<MesurerContextV1>;
|
|
174
199
|
annotations(): Promise<MesurerAnnotation[]>;
|
|
175
200
|
review(annotationId?: string): Promise<MesurerReviewV1 | MesurerReviewV1[]>;
|
|
176
201
|
capturePlan(request?: MesurerContextRequest): Promise<MesurerCapturePlanV1>;
|
|
@@ -186,16 +211,19 @@ export type MesurerArrangeHarness = {
|
|
|
186
211
|
};
|
|
187
212
|
export type MesurerBrowserAgent = MesurerAgentHarness & MesurerContextHarness & MesurerArrangeHarness;
|
|
188
213
|
export type MountedMesurer = {
|
|
189
|
-
element: HTMLDivElement;
|
|
190
|
-
root: HTMLDivElement | ShadowRoot;
|
|
214
|
+
readonly element: HTMLDivElement;
|
|
215
|
+
readonly root: HTMLDivElement | ShadowRoot;
|
|
191
216
|
readonly hostLayer: MesurerHostLayerMode;
|
|
217
|
+
/** @deprecated Await `ready` when direct plugin-host access is required. */
|
|
192
218
|
readonly pluginHost: MesurerPluginHost | undefined;
|
|
193
|
-
|
|
219
|
+
/** Resolves to the live plugin host after startup and initial rendered state settle. */
|
|
220
|
+
readonly ready: Promise<MesurerPluginHost>;
|
|
194
221
|
readonly agent: MesurerBrowserAgent;
|
|
222
|
+
service<T>(id: string): Promise<T>;
|
|
195
223
|
context(request?: MesurerContextRequest): Promise<MesurerContextV1>;
|
|
196
224
|
contextText(request?: MesurerContextRequest): Promise<string>;
|
|
197
225
|
copyContext(request?: MesurerContextRequest): Promise<void>;
|
|
198
|
-
select(selectors: string | string[]): Promise<MesurerContextV1>;
|
|
226
|
+
select(selectors: string | readonly string[]): Promise<MesurerContextV1>;
|
|
199
227
|
annotations(): Promise<MesurerAnnotation[]>;
|
|
200
228
|
review(annotationId?: string): Promise<MesurerReviewV1 | MesurerReviewV1[]>;
|
|
201
229
|
capturePlan(request?: MesurerContextRequest): Promise<MesurerCapturePlanV1>;
|
|
@@ -209,7 +237,7 @@ export type MountedMesurer = {
|
|
|
209
237
|
textEdits(): Promise<MesurerTextEditIntent[]>;
|
|
210
238
|
textEdit(id: string): Promise<MesurerTextEditIntent>;
|
|
211
239
|
bringToFront(): void;
|
|
212
|
-
describe(): MesurerPluginDescription
|
|
240
|
+
describe(): Promise<MesurerPluginDescription>;
|
|
213
241
|
dispose(): void;
|
|
214
242
|
};
|
|
215
243
|
export declare function mountMesurer(options?: MountMesurerOptions): MountedMesurer;
|
|
@@ -224,7 +252,7 @@ export { MESURER_VERSION } from "./version";
|
|
|
224
252
|
export type { AgentDistance, AgentEdges, AgentElementInspection, AgentFeedbackSnapshot, AgentRect, AgentViewportSnapshot, CreateMesurerAgentHarnessOptions, MesurerAgentHarness, MesurerTextEditIntent, MesurerTextEditService, MesurerTextStyleChange, MesurerTextStyleProperty, } from "./agent";
|
|
225
253
|
export type { ArrangeCapturePlan, ArrangeIntent, ArrangeOffset, ArrangePresentation, ArrangeRect, ArrangeReview, ArrangeReviewTarget, ArrangeTarget, MesurerArrangeService, } from "./arrange";
|
|
226
254
|
export { captureMesurerContext, copyTextToClipboard, createMesurerCapturePlan, formatMesurerContext, reviewMesurerAnnotation, } from "./context";
|
|
227
|
-
export type { MesurerAnnotation, MesurerAnnotationBaseline, MesurerAnnotationTarget, MesurerCapturePlanV1, MesurerContextDistance, MesurerContextEdges, MesurerContextGuide, MesurerContextMeasurement, MesurerContextRect, MesurerContextRequest, MesurerContextTarget, MesurerContextV1, MesurerElementFingerprint, MesurerElementInspection, MesurerReviewChange, MesurerReviewMetricChange, MesurerReviewPresenceChange, MesurerReviewV1, } from "./context";
|
|
255
|
+
export type { MesurerAnnotation, MesurerAnnotationBaseline, MesurerAnnotationTarget, MesurerCapturePlanV1, MesurerContextDistance, MesurerContextEdges, MesurerContextGuide, MesurerContextLayoutGuide, MesurerContextMeasurement, MesurerContextRect, MesurerContextRequest, MesurerContextTarget, MesurerContextV1, MesurerElementFingerprint, MesurerElementInspection, MesurerReviewChange, MesurerReviewMetricChange, MesurerReviewPresenceChange, MesurerReviewV1, } from "./context";
|
|
228
256
|
export { createMesurerPluginHost, createMesurerRuntime, defineMesurerPlugin } from "./core";
|
|
229
257
|
export type { CommandHandler as MesurerCommandHandler, MesurerPlugin, MesurerPluginContext, MesurerPluginDescription, MesurerPluginHost, OverlayContribution, Registration as MesurerRegistration, SettingsContribution, StateSliceDefinition, ToolContribution, } from "./core";
|
|
230
258
|
export type { MesurerHostLayerMode } from "./host-layer";
|