mesurer-solid 0.1.2 → 0.1.3-beta.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/AGENT_INTEGRATION.md +166 -154
- package/README.md +188 -232
- package/dist/arrange.d.ts +90 -0
- package/dist/arrange.js +2907 -0
- package/dist/core.js +1 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +4392 -2494
- package/dist/inject-script.js +75 -9
- package/dist/inject.js +4937 -3795
- package/dist/screenshot.js +25 -2
- package/package.json +5 -1
- package/skills/mesurer-ui/SKILL.md +209 -139
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# mesurer-solid
|
|
2
2
|
|
|
3
|
-
Framework-agnostic UI measurement,
|
|
3
|
+
Framework-agnostic UI measurement, visual inspection, layout intent, and agent-ready rendered context for browser applications.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Mesurer's private renderer uses Solid 2. Consumer applications can use Solid 1/2, React, Vue, Svelte, vanilla DOM, or Electron renderer pages without providing Solid.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -14,166 +14,182 @@ bun add -d mesurer-solid
|
|
|
14
14
|
npm install -D mesurer-solid
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Use
|
|
17
|
+
Use `mesurer-solid@beta` only when intentionally testing a prerelease.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
bun add -d mesurer-solid@beta
|
|
21
|
-
# or
|
|
22
|
-
npm install -D mesurer-solid@beta
|
|
23
|
-
```
|
|
19
|
+
Prereleases through `0.1.0-beta.11` used the old scoped package name. Current releases use `mesurer-solid`.
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
## Where Mesurer code goes
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
Mesurer runs in the browser. Mount it once from a client/browser entry for the page you want to inspect.
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
import { mountMesurer } from "mesurer-solid"
|
|
25
|
+
For local development in a Vite app, a clear setup is:
|
|
31
26
|
|
|
32
|
-
|
|
27
|
+
```text
|
|
28
|
+
src/
|
|
29
|
+
├── main.tsx
|
|
30
|
+
└── dev/
|
|
31
|
+
└── mesurer.ts
|
|
33
32
|
```
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
## Add shared visual context
|
|
38
|
-
|
|
39
|
-
Context and annotations are provided by removable `mesurer.context`:
|
|
34
|
+
Create `src/dev/mesurer.ts`:
|
|
40
35
|
|
|
41
36
|
```ts
|
|
42
|
-
import {
|
|
43
|
-
contextPlugin,
|
|
44
|
-
mountMesurer,
|
|
45
|
-
} from "mesurer-solid"
|
|
37
|
+
import { mountMesurer } from "mesurer-solid"
|
|
46
38
|
|
|
47
|
-
const mesurer = mountMesurer(
|
|
48
|
-
|
|
49
|
-
|
|
39
|
+
const mesurer = mountMesurer()
|
|
40
|
+
|
|
41
|
+
import.meta.hot?.dispose(() => {
|
|
42
|
+
mesurer.dispose()
|
|
50
43
|
})
|
|
51
44
|
```
|
|
52
45
|
|
|
53
|
-
|
|
46
|
+
Load it from the existing browser entry:
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
```ts
|
|
49
|
+
if (import.meta.env.DEV) {
|
|
50
|
+
void import("./dev/mesurer")
|
|
51
|
+
}
|
|
52
|
+
```
|
|
56
53
|
|
|
57
|
-
|
|
54
|
+
`import.meta.env.DEV` and `import.meta.hot` are Vite-specific. With another bundler, use its development flag and HMR lifecycle.
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
human evidence OR agent-known affected target
|
|
61
|
-
→ window.__MESURER__
|
|
62
|
-
→ context() / select() / review()
|
|
63
|
-
→ structured rendered evidence
|
|
64
|
-
→ source edit
|
|
65
|
-
→ render settles
|
|
66
|
-
→ fresh context/review
|
|
67
|
-
```
|
|
56
|
+
Do not put `mountMesurer()` in build configuration, API/server routes, Node-only scripts, an Electron main process, or a shared SSR module that also runs on the server.
|
|
68
57
|
|
|
69
|
-
|
|
58
|
+
Typical browser entry locations:
|
|
70
59
|
|
|
71
|
-
|
|
60
|
+
| Application | Typical location |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| React + Vite | `src/main.tsx` |
|
|
63
|
+
| Solid + Vite | `src/index.tsx`, `src/main.tsx`, or the project browser entry |
|
|
64
|
+
| Vue + Vite | `src/main.ts` |
|
|
65
|
+
| Svelte + Vite | `src/main.ts` |
|
|
66
|
+
| Vanilla Vite | `src/main.ts` or `src/main.js` |
|
|
67
|
+
| Electron | renderer entry such as `src/renderer.ts` or `src/renderer/main.tsx` |
|
|
68
|
+
| SSR / metaframework | client-only module or lifecycle that never executes during SSR |
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
const hasMesurer = Boolean(
|
|
75
|
-
window.__MESURER__ &&
|
|
76
|
-
window.__MESURER_INSTANCE__?.element?.isConnected
|
|
77
|
-
)
|
|
70
|
+
Put plugin setup in that same Mesurer module.
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
await window.__MESURER__.ready()
|
|
81
|
-
}
|
|
82
|
-
```
|
|
72
|
+
## Base inspector
|
|
83
73
|
|
|
84
|
-
|
|
74
|
+
```ts
|
|
75
|
+
import { mountMesurer } from "mesurer-solid"
|
|
85
76
|
|
|
86
|
-
|
|
87
|
-
window.__MESURER_CONFIG__ = { reuseExisting: false }
|
|
77
|
+
const mesurer = mountMesurer()
|
|
88
78
|
```
|
|
89
79
|
|
|
90
|
-
|
|
80
|
+
The base inspector includes Select, X-ray, Color Picker, Rulers, Text Inspector, Guides, Distance, Settings, the plugin host, and the low-level inspection API.
|
|
91
81
|
|
|
92
|
-
##
|
|
82
|
+
## Arrange
|
|
93
83
|
|
|
94
|
-
|
|
95
|
-
import { readFile } from "node:fs/promises"
|
|
96
|
-
import { fileURLToPath } from "node:url"
|
|
84
|
+
Arrange is an optional first-party plugin for showing how selected rendered elements should be positioned without pretending to edit application source.
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
)
|
|
86
|
+
```ts
|
|
87
|
+
import { mountMesurer } from "mesurer-solid"
|
|
88
|
+
import { arrangePlugin } from "mesurer-solid/arrange"
|
|
102
89
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
const mesurer = mountMesurer({
|
|
91
|
+
plugins: [arrangePlugin()],
|
|
92
|
+
})
|
|
93
|
+
```
|
|
107
94
|
|
|
108
|
-
|
|
109
|
-
await browser.evaluate(source)
|
|
110
|
-
}
|
|
95
|
+
Select one or more page elements, click **Arrange**, and drag the selection. Hold **Shift** while dragging to lock movement to the dominant axis.
|
|
111
96
|
|
|
112
|
-
|
|
113
|
-
```
|
|
97
|
+
Each completed drag records one persisted, undoable intent containing:
|
|
114
98
|
|
|
115
|
-
|
|
99
|
+
- target selector and fingerprint;
|
|
100
|
+
- Before geometry;
|
|
101
|
+
- Desired geometry;
|
|
102
|
+
- previous and Desired visual offsets;
|
|
103
|
+
- page scope;
|
|
104
|
+
- creation time.
|
|
116
105
|
|
|
117
|
-
|
|
118
|
-
window.__MESURER_CONFIG__ = { context: false }
|
|
119
|
-
```
|
|
106
|
+
Arrange only changes the temporary browser presentation. It does not write CSS, component source, templates, or application state.
|
|
120
107
|
|
|
121
|
-
|
|
108
|
+
### Arrange with a coding agent
|
|
122
109
|
|
|
123
|
-
|
|
124
|
-
window.__MESURER_CONFIG__ = { screenshot: true }
|
|
125
|
-
```
|
|
110
|
+
For the full agent workflow, mount context and Arrange together:
|
|
126
111
|
|
|
127
|
-
|
|
112
|
+
```ts
|
|
113
|
+
import {
|
|
114
|
+
contextPlugin,
|
|
115
|
+
mountMesurer,
|
|
116
|
+
} from "mesurer-solid"
|
|
117
|
+
import { arrangePlugin } from "mesurer-solid/arrange"
|
|
128
118
|
|
|
129
|
-
|
|
119
|
+
const mesurer = mountMesurer({
|
|
120
|
+
agent: true,
|
|
121
|
+
plugins: [
|
|
122
|
+
contextPlugin(),
|
|
123
|
+
arrangePlugin(),
|
|
124
|
+
],
|
|
125
|
+
})
|
|
126
|
+
```
|
|
130
127
|
|
|
131
|
-
|
|
128
|
+
The agent capability surface then includes `arrange: true` and can read saved intents:
|
|
132
129
|
|
|
133
130
|
```js
|
|
134
|
-
window.__MESURER__.
|
|
131
|
+
const intents = await window.__MESURER__.arrangements()
|
|
132
|
+
const intent = await window.__MESURER__.arrange(intents.at(-1).id)
|
|
135
133
|
```
|
|
136
134
|
|
|
137
|
-
|
|
135
|
+
Arrange distinguishes three states:
|
|
138
136
|
|
|
139
137
|
```text
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
review
|
|
144
|
-
capturePlan
|
|
138
|
+
Before → original presentation before the Arrange action
|
|
139
|
+
Desired → human-arranged visual result
|
|
140
|
+
Live → real application result with Arrange preview removed
|
|
145
141
|
```
|
|
146
142
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
### Read the whole workspace
|
|
143
|
+
The agent can reconstruct Before and Desired before editing source:
|
|
150
144
|
|
|
151
145
|
```js
|
|
152
|
-
|
|
146
|
+
await window.__MESURER__.showArrange(intent.id, "before")
|
|
147
|
+
const beforePlan = await window.__MESURER__.arrangeCapturePlan(intent.id, "before")
|
|
148
|
+
|
|
149
|
+
await window.__MESURER__.showArrange(intent.id, "desired")
|
|
150
|
+
const desiredPlan = await window.__MESURER__.arrangeCapturePlan(intent.id, "desired")
|
|
153
151
|
```
|
|
154
152
|
|
|
155
|
-
|
|
153
|
+
The outer browser harness owns screenshot bytes. Mesurer supplies the exact state and capture geometry, so the person does not need to export or attach Before/Desired screenshots manually.
|
|
156
154
|
|
|
157
|
-
|
|
155
|
+
After source edits:
|
|
158
156
|
|
|
159
157
|
```js
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
} catch {}
|
|
158
|
+
await window.__MESURER__.stable()
|
|
159
|
+
await window.__MESURER__.showArrange(intent.id, "live")
|
|
160
|
+
const review = await window.__MESURER__.reviewArrange(intent.id)
|
|
164
161
|
```
|
|
165
162
|
|
|
166
|
-
|
|
163
|
+
`reviewArrange()` reports exact Live-vs-Desired rectangle deltas and conservative target status.
|
|
164
|
+
|
|
165
|
+
A drag is a visual specification, not a CSS prescription. If a person moves something `96px` right, the coding agent should determine the appropriate flex/grid/gap/margin/component change rather than blindly writing a `translateX(96px)` production transform.
|
|
167
166
|
|
|
168
|
-
|
|
167
|
+
See the repository's [`docs/ARRANGE.md`](https://github.com/jhomra21/mesurer-solid/blob/main/docs/ARRANGE.md) for the full workflow.
|
|
169
168
|
|
|
170
|
-
|
|
169
|
+
## Shared visual context
|
|
170
|
+
|
|
171
|
+
Context and annotations are provided by the optional `mesurer.context` plugin:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import {
|
|
175
|
+
contextPlugin,
|
|
176
|
+
mountMesurer,
|
|
177
|
+
} from "mesurer-solid"
|
|
178
|
+
|
|
179
|
+
const mesurer = mountMesurer({
|
|
180
|
+
agent: true,
|
|
181
|
+
plugins: [contextPlugin()],
|
|
182
|
+
})
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Read the workspace or current human selection:
|
|
171
186
|
|
|
172
187
|
```js
|
|
173
|
-
const
|
|
188
|
+
const workspace = await window.__MESURER__.context()
|
|
189
|
+
const selection = await window.__MESURER__.context({ scope: "selection" })
|
|
174
190
|
```
|
|
175
191
|
|
|
176
|
-
|
|
192
|
+
Select exact rendered targets and get their context back:
|
|
177
193
|
|
|
178
194
|
```js
|
|
179
195
|
const context = await window.__MESURER__.select([
|
|
@@ -182,94 +198,70 @@ const context = await window.__MESURER__.select([
|
|
|
182
198
|
])
|
|
183
199
|
```
|
|
184
200
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
1. enables Mesurer and switches to Select;
|
|
188
|
-
2. visibly highlights those rendered elements;
|
|
189
|
-
3. makes them the live selection;
|
|
190
|
-
4. waits for the selection to settle;
|
|
191
|
-
5. returns selection-scoped `MesurerContextV1`.
|
|
201
|
+
Every selector must resolve to exactly one page target. Invalid, missing, or ambiguous selectors throw instead of guessing.
|
|
192
202
|
|
|
193
|
-
|
|
203
|
+
`MesurerContextV1` includes rendered geometry, box model, typography, appearance, flex/grid layout, transforms, scroll/overflow, guides, measurements, distances, selected targets, and annotated regions.
|
|
194
204
|
|
|
195
|
-
|
|
205
|
+
## Annotations and review
|
|
196
206
|
|
|
197
|
-
|
|
207
|
+
A human annotation stores a note plus an immutable rendered baseline:
|
|
198
208
|
|
|
199
209
|
```js
|
|
200
|
-
await window.__MESURER__.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
changedSelectorB,
|
|
205
|
-
])
|
|
210
|
+
const annotations = await window.__MESURER__.annotations()
|
|
211
|
+
const context = await window.__MESURER__.context({
|
|
212
|
+
annotation: annotations[0].id,
|
|
213
|
+
})
|
|
206
214
|
```
|
|
207
215
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
## Multi-selection
|
|
211
|
-
|
|
212
|
-
For every selected target, context contains selector/identity, rect, margin/padding/border, typography, appearance, layout, and scroll/overflow.
|
|
213
|
-
|
|
214
|
-
Use existing `visualContext.distances` first, then `distance(selectorA, selectorB)` for selected pairs whose relationship is not already represented. Small multi-selections should expose useful pairwise pixel relationships rather than merely saying “3 elements selected.”
|
|
215
|
-
|
|
216
|
-
## Saved annotations
|
|
216
|
+
After a source change:
|
|
217
217
|
|
|
218
218
|
```js
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
for (const annotation of annotations) {
|
|
222
|
-
const context = await window.__MESURER__.context({ annotation: annotation.id })
|
|
223
|
-
}
|
|
219
|
+
await window.__MESURER__.stable()
|
|
220
|
+
const review = await window.__MESURER__.review(annotationId)
|
|
224
221
|
```
|
|
225
222
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
## Agent target-acquisition rule
|
|
223
|
+
Review reports concrete pixel changes and missing evidence rather than relying on source assumptions.
|
|
229
224
|
|
|
230
|
-
|
|
225
|
+
## Agent integration
|
|
231
226
|
|
|
232
|
-
|
|
233
|
-
2. no relevant selection and intended target is ambiguous → ask the human to select it, then read selection context;
|
|
234
|
-
3. no relevant selection and agent knows exact affected rendered targets → call `select()` and consume the returned context.
|
|
227
|
+
The coding-agent contract is context-first and preserves existing human state:
|
|
235
228
|
|
|
236
|
-
|
|
229
|
+
```text
|
|
230
|
+
human Arrange / annotation / selection
|
|
231
|
+
→ window.__MESURER__
|
|
232
|
+
→ structured rendered evidence
|
|
233
|
+
→ source edit
|
|
234
|
+
→ real render / HMR
|
|
235
|
+
→ fresh Live review/context
|
|
236
|
+
```
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
There is no Mesurer MCP, WebMCP, ACP, localhost feedback daemon, Send-to-agent callback, or chat/session routing.
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
Before injecting anything, reuse a live Mesurer instance if one is already present:
|
|
241
241
|
|
|
242
242
|
```js
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
243
|
+
const hasMesurer = Boolean(
|
|
244
|
+
window.__MESURER__ &&
|
|
245
|
+
window.__MESURER_INSTANCE__?.element?.isConnected
|
|
246
|
+
)
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
if (hasMesurer) {
|
|
249
|
+
await window.__MESURER__.ready()
|
|
250
|
+
}
|
|
250
251
|
```
|
|
251
252
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
```js
|
|
255
|
-
const after = await window.__MESURER__.context({ scope: "selection" })
|
|
256
|
-
```
|
|
253
|
+
A live human instance may already contain the information the agent needs. Do not overwrite selection, Arrange history, guides, measurements, annotations, or screenshot preview state before reading it.
|
|
257
254
|
|
|
258
|
-
|
|
255
|
+
Install the portable Agent Skill with:
|
|
259
256
|
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
changedSelectorA,
|
|
263
|
-
changedSelectorB,
|
|
264
|
-
])
|
|
257
|
+
```bash
|
|
258
|
+
npx --yes --package=mesurer-solid mesurer-skill install
|
|
265
259
|
```
|
|
266
260
|
|
|
267
|
-
For
|
|
261
|
+
For detailed agent rules, use [`AGENT_INTEGRATION.md`](./AGENT_INTEGRATION.md).
|
|
268
262
|
|
|
269
263
|
## Optional screenshot plugin
|
|
270
264
|
|
|
271
|
-
Screenshot capture is a removable first-party plugin instead of permanent core state:
|
|
272
|
-
|
|
273
265
|
```ts
|
|
274
266
|
import { mountMesurer } from "mesurer-solid"
|
|
275
267
|
import { screenshotPlugin } from "mesurer-solid/screenshot"
|
|
@@ -284,98 +276,62 @@ const mesurer = mountMesurer({
|
|
|
284
276
|
})
|
|
285
277
|
```
|
|
286
278
|
|
|
287
|
-
The camera tool
|
|
288
|
-
|
|
289
|
-
A successful capture can automatically copy PNG data to the clipboard and/or download a PNG according to persistent plugin settings. Those output operations are best-effort: if clipboard or download access is unavailable, the captured PNG is still kept for preview/viewer use and Mesurer reports the available result instead of discarding it.
|
|
290
|
-
|
|
291
|
-
When `contextPlugin()` and/or `screenshotPlugin()` are mounted, Settings → General → Plugins exposes compact persisted controls for the human-facing plugin surface. Context can hide or restore its toolbar/annotation controls without removing the typed context service. Screenshot can hide or restore the camera tool and control automatic copy, automatic download, and whether measurement presentation is included in captured pixels.
|
|
292
|
-
|
|
293
|
-
After capture, Mesurer shows a persistent draggable thumbnail. A new thumbnail starts in the bottom-right with an 8px viewport inset. Dragging preserves the existing viewport-clamping behavior, so the preview stays inside that safe boundary. The thumbnail can be dismissed, dragged around the viewport, right-clicked with the browser's native image context menu, or clicked to open a larger viewer. The viewer preserves native image right-click behavior and adds explicit Copy, Save, and Close controls. Escape or backdrop click closes the viewer without discarding the thumbnail. A short status message confirms whether the screenshot was copied, saved, captured, or could not complete an optional output.
|
|
294
|
-
|
|
295
|
-
Normal browser hosts use `getDisplayMedia()` and reuse a live capture stream to avoid prompting for every region. The first-party Chrome extension uses `chrome.tabs.captureVisibleTab()` through its isolated-world extension bridge, so its screenshot path does not open the screen-share chooser and does not require a broad `<all_urls>` permission.
|
|
296
|
-
|
|
297
|
-
Programmatic mounted users can get the typed `MesurerScreenshotService` from the plugin host with service id `screenshot`. `start()` opens region selection, `cancel()` closes it, `capture(rect)` captures an exact CSS-pixel viewport rectangle, `settings()` reads copy/download preferences, and `setSettings()` updates those persistent preferences.
|
|
279
|
+
The human camera tool supports drag-region visible-tab capture, HiDPI/Retina-aware PNG cropping, copy/download settings, a draggable thumbnail, and a larger Copy/Save viewer.
|
|
298
280
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
## Clean screenshot evidence for agents
|
|
302
|
-
|
|
303
|
-
The optional screenshot plugin is a human capture tool, not an agent-delivery channel. Agent verification can continue to let the existing browser harness own deterministic task screenshots while Mesurer plans a clean evidence frame:
|
|
281
|
+
For coding-agent verification, the outer browser harness should normally own screenshot bytes. Mesurer supplies exact capture scope and can temporarily remove inspector presentation:
|
|
304
282
|
|
|
305
283
|
```js
|
|
306
284
|
const plan = await window.__MESURER__.capturePlan({ scope: "selection" })
|
|
285
|
+
|
|
307
286
|
await window.__MESURER__.prepareCapture()
|
|
308
287
|
try {
|
|
309
|
-
//
|
|
288
|
+
// use the harness screenshot primitive
|
|
310
289
|
} finally {
|
|
311
290
|
await window.__MESURER__.finishCapture()
|
|
312
291
|
}
|
|
313
292
|
```
|
|
314
293
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
## Context UI
|
|
318
|
-
|
|
319
|
-
With default `contextPlugin()` UI:
|
|
320
|
-
|
|
321
|
-
| Action | Shortcut | What it does |
|
|
322
|
-
| --- | --- | --- |
|
|
323
|
-
| Copy Context | `C` | Copies current workspace context. |
|
|
324
|
-
| Copy Selection | `Shift+C` | Copies context scoped to selected element(s) or region. |
|
|
325
|
-
| Add Note | `N` | Creates a durable annotation baseline. |
|
|
326
|
-
|
|
327
|
-
Those remain the three human context controls. `select()` is a programmatic agent/harness API, not another toolbar action.
|
|
328
|
-
|
|
329
|
-
## Portable Agent Skill
|
|
330
|
-
|
|
331
|
-
```bash
|
|
332
|
-
npx --yes --package=mesurer-solid mesurer-skill install
|
|
333
|
-
```
|
|
294
|
+
## Public entry points
|
|
334
295
|
|
|
335
|
-
|
|
296
|
+
```ts
|
|
297
|
+
import {
|
|
298
|
+
contextPlugin,
|
|
299
|
+
defineMesurerPlugin,
|
|
300
|
+
mountMesurer,
|
|
301
|
+
} from "mesurer-solid"
|
|
336
302
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
└── assets/
|
|
341
|
-
└── inject-script.js
|
|
303
|
+
import { arrangePlugin } from "mesurer-solid/arrange"
|
|
304
|
+
import { createMesurerPluginHost } from "mesurer-solid/core"
|
|
305
|
+
import { screenshotPlugin } from "mesurer-solid/screenshot"
|
|
342
306
|
```
|
|
343
307
|
|
|
344
|
-
The
|
|
345
|
-
|
|
346
|
-
## Low-level agent API
|
|
347
|
-
|
|
348
|
-
Regardless of the context plugin:
|
|
308
|
+
The transport-neutral classic browser payload is:
|
|
349
309
|
|
|
350
310
|
```text
|
|
351
|
-
|
|
352
|
-
inspect / inspectAll / at
|
|
353
|
-
distance / viewport / feedback
|
|
354
|
-
describe / command / state
|
|
311
|
+
mesurer-solid/inject-script
|
|
355
312
|
```
|
|
356
313
|
|
|
357
|
-
|
|
314
|
+
## Supported hosts
|
|
358
315
|
|
|
359
|
-
|
|
316
|
+
Mesurer's renderer is bundled and isolated from the host framework. Supported host classes include:
|
|
360
317
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
318
|
+
- Solid 1
|
|
319
|
+
- Solid 2
|
|
320
|
+
- React
|
|
321
|
+
- Vue
|
|
322
|
+
- Svelte
|
|
323
|
+
- vanilla DOM applications
|
|
324
|
+
- Electron renderer pages
|
|
368
325
|
|
|
369
|
-
|
|
326
|
+
## More documentation
|
|
370
327
|
|
|
371
|
-
|
|
328
|
+
- [Getting started](https://github.com/jhomra21/mesurer-solid/blob/main/docs/GETTING_STARTED.md)
|
|
329
|
+
- [Arrange](https://github.com/jhomra21/mesurer-solid/blob/main/docs/ARRANGE.md)
|
|
330
|
+
- [Context workflow](https://github.com/jhomra21/mesurer-solid/blob/main/docs/CONTEXT_WORKFLOW.md)
|
|
331
|
+
- [Screenshots](https://github.com/jhomra21/mesurer-solid/blob/main/docs/SCREENSHOTS.md)
|
|
332
|
+
- [Host isolation](https://github.com/jhomra21/mesurer-solid/blob/main/docs/HOST_ISOLATION.md)
|
|
333
|
+
- [Agent integration](./AGENT_INTEGRATION.md)
|
|
372
334
|
|
|
373
|
-
|
|
374
|
-
mesurer-solid
|
|
375
|
-
mesurer-solid/core
|
|
376
|
-
mesurer-solid/screenshot
|
|
377
|
-
mesurer-solid/inject
|
|
378
|
-
mesurer-solid/inject-script
|
|
379
|
-
```
|
|
335
|
+
## License
|
|
380
336
|
|
|
381
|
-
MIT
|
|
337
|
+
MIT
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { MesurerPlugin } from "./core";
|
|
2
|
+
export declare const MESURER_ARRANGE_ACTIVE_STATE_ID: string;
|
|
3
|
+
export declare const MESURER_ARRANGE_PLUGIN_ID: string;
|
|
4
|
+
export declare const MESURER_ARRANGE_SERVICE_ID: string;
|
|
5
|
+
export declare const MESURER_ARRANGE_SETTINGS_STATE_ID: string;
|
|
6
|
+
export declare const MESURER_ARRANGE_STATE_ID: string;
|
|
7
|
+
export type ArrangeRect = {
|
|
8
|
+
left: number;
|
|
9
|
+
top: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
};
|
|
13
|
+
export type ArrangeOffset = {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
};
|
|
17
|
+
export type ArrangeElementFingerprint = {
|
|
18
|
+
tag: string;
|
|
19
|
+
id: string | null;
|
|
20
|
+
testId: string | null;
|
|
21
|
+
role: string | null;
|
|
22
|
+
ariaLabel: string | null;
|
|
23
|
+
classes: string[];
|
|
24
|
+
text: string | null;
|
|
25
|
+
};
|
|
26
|
+
export type ArrangeTarget = {
|
|
27
|
+
id: string;
|
|
28
|
+
selector: string;
|
|
29
|
+
fingerprint: ArrangeElementFingerprint;
|
|
30
|
+
before: ArrangeRect;
|
|
31
|
+
desired: ArrangeRect;
|
|
32
|
+
beforeOffset: ArrangeOffset;
|
|
33
|
+
desiredOffset: ArrangeOffset;
|
|
34
|
+
};
|
|
35
|
+
export type ArrangeIntent = {
|
|
36
|
+
id: string;
|
|
37
|
+
createdAt: number;
|
|
38
|
+
pageUrl: string;
|
|
39
|
+
targets: ArrangeTarget[];
|
|
40
|
+
};
|
|
41
|
+
export type ArrangePresentation = "before" | "desired" | "live";
|
|
42
|
+
export type ArrangeReviewTarget = {
|
|
43
|
+
targetId: string;
|
|
44
|
+
selector: string;
|
|
45
|
+
desired: ArrangeRect;
|
|
46
|
+
current: ArrangeRect | null;
|
|
47
|
+
delta: ArrangeRect | null;
|
|
48
|
+
matched: boolean;
|
|
49
|
+
};
|
|
50
|
+
export type ArrangeReview = {
|
|
51
|
+
schema: "mesurer.arrange-review/v1";
|
|
52
|
+
arrangeId: string;
|
|
53
|
+
targetStatus: "connected" | "partial" | "stale";
|
|
54
|
+
tolerance: number;
|
|
55
|
+
matched: boolean;
|
|
56
|
+
targets: ArrangeReviewTarget[];
|
|
57
|
+
};
|
|
58
|
+
export type ArrangeCapturePlan = {
|
|
59
|
+
schema: "mesurer.arrange-capture/v1";
|
|
60
|
+
arrangeId: string;
|
|
61
|
+
state: ArrangePresentation;
|
|
62
|
+
chrome: "hide";
|
|
63
|
+
captures: Array<{
|
|
64
|
+
id: "viewport";
|
|
65
|
+
kind: "viewport";
|
|
66
|
+
} | {
|
|
67
|
+
id: "focus";
|
|
68
|
+
kind: "clip";
|
|
69
|
+
rect: ArrangeRect;
|
|
70
|
+
}>;
|
|
71
|
+
};
|
|
72
|
+
export type MesurerArrangeSettings = {
|
|
73
|
+
snapping: boolean;
|
|
74
|
+
elementEdges: boolean;
|
|
75
|
+
elementCenters: boolean;
|
|
76
|
+
guides: boolean;
|
|
77
|
+
preferXrayEdges: boolean;
|
|
78
|
+
snapLines: boolean;
|
|
79
|
+
};
|
|
80
|
+
export type MesurerArrangeService = {
|
|
81
|
+
active(): boolean;
|
|
82
|
+
intents(): ArrangeIntent[];
|
|
83
|
+
intent(id: string): ArrangeIntent | null;
|
|
84
|
+
show(id: string, state: ArrangePresentation): void;
|
|
85
|
+
showCurrent(): void;
|
|
86
|
+
capturePlan(id: string, state: ArrangePresentation): ArrangeCapturePlan;
|
|
87
|
+
review(id: string, tolerance?: number): ArrangeReview;
|
|
88
|
+
clear(): Promise<void>;
|
|
89
|
+
};
|
|
90
|
+
export declare const arrangePlugin: () => MesurerPlugin;
|