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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # mesurer-solid
2
2
 
3
- Framework-agnostic UI measurement, annotation, inspection, and agent-ready visual context for browser applications.
3
+ Framework-agnostic UI measurement, visual inspection, layout intent, and agent-ready rendered context for browser applications.
4
4
 
5
- The renderer is implemented privately in Solid 2, but consumers can use Solid 1/2, React, Vue, Svelte, vanilla DOM, or Electron renderer pages without providing Solid.
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 the `beta` tag only when you intentionally want to test a prerelease:
17
+ Use `mesurer-solid@beta` only when intentionally testing a prerelease.
18
18
 
19
- ```bash
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
- Prereleases through `0.1.0-beta.11` used the old scoped package name; current releases use `mesurer-solid`.
21
+ ## Where Mesurer code goes
26
22
 
27
- ## Mount the base inspector
23
+ Mesurer runs in the browser. Mount it once from a client/browser entry for the page you want to inspect.
28
24
 
29
- ```ts
30
- import { mountMesurer } from "mesurer-solid"
25
+ For local development in a Vite app, a clear setup is:
31
26
 
32
- const mesurer = mountMesurer()
27
+ ```text
28
+ src/
29
+ ├── main.tsx
30
+ └── dev/
31
+ └── mesurer.ts
33
32
  ```
34
33
 
35
- The base inspector contains Select, X-ray, Color Picker, Rulers, Text Inspector, Guides, Distance, Settings, the plugin host, and the low-level agent inspection API.
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
- agent: true,
49
- plugins: [contextPlugin()],
39
+ const mesurer = mountMesurer()
40
+
41
+ import.meta.hot?.dispose(() => {
42
+ mesurer.dispose()
50
43
  })
51
44
  ```
52
45
 
53
- The human can select one or multiple elements, drag regions, place guides, create measurements/held distances, enable rulers/X-ray, and save annotation notes/baselines.
46
+ Load it from the existing browser entry:
54
47
 
55
- The coding agent reads that same rendered state directly from the page. There is no Mesurer MCP, WebMCP, ACP, localhost feedback daemon, Send-to-agent callback, or chat/session routing.
48
+ ```ts
49
+ if (import.meta.env.DEV) {
50
+ void import("./dev/mesurer")
51
+ }
52
+ ```
56
53
 
57
- The agent contract is **context-first**: Mesurer visual operations should produce structured context the agent actually consumes.
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
- ```text
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
- ## Preserve a live human instance
58
+ Typical browser entry locations:
70
59
 
71
- Before injecting anything:
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
- ```js
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
- if (hasMesurer) {
80
- await window.__MESURER__.ready()
81
- }
82
- ```
72
+ ## Base inspector
83
73
 
84
- If Mesurer already exists, reuse it and read existing human state before changing the selection. Injected Mesurer preserves a live instance by default. Deliberate replacement requires:
74
+ ```ts
75
+ import { mountMesurer } from "mesurer-solid"
85
76
 
86
- ```js
87
- window.__MESURER_CONFIG__ = { reuseExisting: false }
77
+ const mesurer = mountMesurer()
88
78
  ```
89
79
 
90
- That option is for explicit test/tooling replacement, not normal agent attachment.
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
- ## Inject only when absent
82
+ ## Arrange
93
83
 
94
- ```js
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
- const source = await readFile(
99
- fileURLToPath(import.meta.resolve("mesurer-solid/inject-script")),
100
- "utf8",
101
- )
86
+ ```ts
87
+ import { mountMesurer } from "mesurer-solid"
88
+ import { arrangePlugin } from "mesurer-solid/arrange"
102
89
 
103
- const hasMesurer = await browser.evaluate(() => Boolean(
104
- window.__MESURER__ &&
105
- window.__MESURER_INSTANCE__?.element?.isConnected
106
- ))
90
+ const mesurer = mountMesurer({
91
+ plugins: [arrangePlugin()],
92
+ })
93
+ ```
107
94
 
108
- if (!hasMesurer) {
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
- await browser.evaluate(() => window.__MESURER__.ready())
113
- ```
97
+ Each completed drag records one persisted, undoable intent containing:
114
98
 
115
- Injection installs `contextPlugin()` by default. To deliberately inject only the low-level inspector:
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
- ```js
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
- Screenshot capture remains opt-in for normal injection:
108
+ ### Arrange with a coding agent
122
109
 
123
- ```js
124
- window.__MESURER_CONFIG__ = { screenshot: true }
125
- ```
110
+ For the full agent workflow, mount context and Arrange together:
126
111
 
127
- The first-party Chrome extension enables screenshot capture automatically.
112
+ ```ts
113
+ import {
114
+ contextPlugin,
115
+ mountMesurer,
116
+ } from "mesurer-solid"
117
+ import { arrangePlugin } from "mesurer-solid/arrange"
128
118
 
129
- ## Direct context API
119
+ const mesurer = mountMesurer({
120
+ agent: true,
121
+ plugins: [
122
+ contextPlugin(),
123
+ arrangePlugin(),
124
+ ],
125
+ })
126
+ ```
130
127
 
131
- With the context plugin loaded:
128
+ The agent capability surface then includes `arrange: true` and can read saved intents:
132
129
 
133
130
  ```js
134
- window.__MESURER__.capabilities().capabilities
131
+ const intents = await window.__MESURER__.arrangements()
132
+ const intent = await window.__MESURER__.arrange(intents.at(-1).id)
135
133
  ```
136
134
 
137
- exposes:
135
+ Arrange distinguishes three states:
138
136
 
139
137
  ```text
140
- context
141
- select
142
- annotations
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
- There is no send/delivery capability or `sendContext()`.
148
-
149
- ### Read the whole workspace
143
+ The agent can reconstruct Before and Desired before editing source:
150
144
 
151
145
  ```js
152
- const workspace = await window.__MESURER__.context()
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
- Workspace context includes page/viewport state, rulers/X-ray visibility, targets, guides, measurements, held distances, exact rects, box model, typography, appearance, layout, scroll size, and overflow.
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
- ### Read the current human selection
155
+ After source edits:
158
156
 
159
157
  ```js
160
- let selection = null
161
- try {
162
- selection = await window.__MESURER__.context({ scope: "selection" })
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
- Selection context answers what the human is pointing at now. Preserve and consume it before programmatically changing selection.
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
- ### Select exact rendered targets and get context back
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
- When an agent knows exactly which rendered element it wants to highlight/verify, it can select it itself:
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 context = await window.__MESURER__.select("#pricing-card")
188
+ const workspace = await window.__MESURER__.context()
189
+ const selection = await window.__MESURER__.context({ scope: "selection" })
174
190
  ```
175
191
 
176
- For several exact targets:
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
- `select()`:
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
- The return value is intentional. Agents should consume it rather than treating the highlight as the end of the operation.
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
- Every selector must resolve to exactly one element inside the page target. Invalid, missing, or ambiguous selectors throw. Refine the selector or ask the human to select the intended target rather than guessing.
205
+ ## Annotations and review
196
206
 
197
- This gives agents a clean post-edit verification pattern:
207
+ A human annotation stores a note plus an immutable rendered baseline:
198
208
 
199
209
  ```js
200
- await window.__MESURER__.stable()
201
-
202
- const evidence = await window.__MESURER__.select([
203
- changedSelectorA,
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
- The user sees what the agent changed, and the agent receives the exact rendered evidence in the same operation.
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
- const annotations = await window.__MESURER__.annotations()
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
- An annotation adds a durable note and immutable baseline. The note is human intent; geometry/computed styles/guides/distances/screenshots are supporting evidence.
227
-
228
- ## Agent target-acquisition rule
223
+ Review reports concrete pixel changes and missing evidence rather than relying on source assumptions.
229
224
 
230
- When Mesurer is available, agents should follow this order:
225
+ ## Agent integration
231
226
 
232
- 1. existing relevant human selection/annotation → read it first;
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
- Do not ask the user to select something the agent can identify exactly itself. Do not guess when the target truly is ambiguous.
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
- ## Verify the rendered fix
238
+ There is no Mesurer MCP, WebMCP, ACP, localhost feedback daemon, Send-to-agent callback, or chat/session routing.
239
239
 
240
- After source edits and the real page update:
240
+ Before injecting anything, reuse a live Mesurer instance if one is already present:
241
241
 
242
242
  ```js
243
- await window.__MESURER__.stable()
244
- ```
245
-
246
- For a saved annotation:
243
+ const hasMesurer = Boolean(
244
+ window.__MESURER__ &&
245
+ window.__MESURER_INSTANCE__?.element?.isConnected
246
+ )
247
247
 
248
- ```js
249
- const review = await window.__MESURER__.review(annotationId)
248
+ if (hasMesurer) {
249
+ await window.__MESURER__.ready()
250
+ }
250
251
  ```
251
252
 
252
- For a still-relevant human selection:
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
- When the agent knows the affected rendered targets:
255
+ Install the portable Agent Skill with:
259
256
 
260
- ```js
261
- const after = await window.__MESURER__.select([
262
- changedSelectorA,
263
- changedSelectorB,
264
- ])
257
+ ```bash
258
+ npx --yes --package=mesurer-solid mesurer-skill install
265
259
  ```
266
260
 
267
- For meaningful visual work, fresh Mesurer context/review is part of completion. Lint, typecheck, tests, and build are implementation checks, not rendered proof.
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 lets the user drag a viewport region. Mesurer captures the real visible page, converts CSS viewport coordinates to the captured bitmap scale so Retina/HiDPI crops remain exact, temporarily hides its control chrome from the pixels, then restores the previous inspector presentation.
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
- Screenshot does not claim the global `C` shortcut because the context workflow already uses `C` and `Shift+C`.
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
- // Capture the real viewport and optional focus crop through the harness.
288
+ // use the harness screenshot primitive
310
289
  } finally {
311
290
  await window.__MESURER__.finishCapture()
312
291
  }
313
292
  ```
314
293
 
315
- Use screenshots for visual composition and Mesurer context for exact numeric claims. A screenshot plugin image does not create a `screenshots` delivery capability on `window.__MESURER__` and does not replace context/select/review evidence.
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
- The installer leaves:
296
+ ```ts
297
+ import {
298
+ contextPlugin,
299
+ defineMesurerPlugin,
300
+ mountMesurer,
301
+ } from "mesurer-solid"
336
302
 
337
- ```text
338
- .agents/skills/mesurer-ui/
339
- ├── SKILL.md
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 skill teaches the context-first workflow, including when to consume human selection, when to ask for a selection, when to self-select changed targets, multi-selection reads, fresh post-edit verification, and the distinction between the optional human screenshot plugin and harness-owned agent screenshot evidence. See [`AGENT_INTEGRATION.md`](./AGENT_INTEGRATION.md).
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
- ready / stable
352
- inspect / inspectAll / at
353
- distance / viewport / feedback
354
- describe / command / state
311
+ mesurer-solid/inject-script
355
312
  ```
356
313
 
357
- Use low-level APIs for narrow measurement questions. Prefer `context()`, `select()`, and `review()` for normal visual work.
314
+ ## Supported hosts
358
315
 
359
- ## Plugins
316
+ Mesurer's renderer is bundled and isolated from the host framework. Supported host classes include:
360
317
 
361
- ```ts
362
- import {
363
- createMesurerPluginHost,
364
- createMesurerRuntime,
365
- defineMesurerPlugin,
366
- } from "mesurer-solid/core"
367
- ```
318
+ - Solid 1
319
+ - Solid 2
320
+ - React
321
+ - Vue
322
+ - Svelte
323
+ - vanilla DOM applications
324
+ - Electron renderer pages
368
325
 
369
- Plugins can contribute tools, commands, hooks, overlays, settings, state, services, history/persistence, renderer-owned UI, and lifecycle cleanup. Plugin-defined toggle settings can register through the plugin host and appear in the canonical General → Plugins Settings section without hard-coding the plugin into Mesurer's renderer.
326
+ ## More documentation
370
327
 
371
- ## Public surface
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
- ```text
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. Adapted from `ibelick/mesurer`; see `THIRD_PARTY_LICENSES.md`.
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;