mesurer-solid 0.1.4 → 0.1.6
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 +144 -21
- package/README.md +74 -33
- package/dist/agent.d.ts +24 -0
- package/dist/arrange.js +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +2409 -1738
- package/dist/inject-script.js +5 -5
- package/dist/inject.js +2408 -1737
- package/dist/screenshot.js +1 -1
- package/package.json +1 -1
- package/skills/mesurer-ui/SKILL.md +175 -28
package/AGENT_INTEGRATION.md
CHANGED
|
@@ -9,7 +9,7 @@ The page is the shared state boundary. A meaningful Mesurer operation should ret
|
|
|
9
9
|
```text
|
|
10
10
|
human visual intent
|
|
11
11
|
↓
|
|
12
|
-
Arrange / annotation / selection
|
|
12
|
+
Arrange / text-style Desired edits / annotation / selection
|
|
13
13
|
↓
|
|
14
14
|
window.__MESURER__
|
|
15
15
|
↓
|
|
@@ -43,7 +43,7 @@ The installed skill is self-contained:
|
|
|
43
43
|
└── inject-script.js
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
The skill defines the same state-preservation, Arrange, context, screenshot, HMR, and completion rules described here.
|
|
46
|
+
The skill defines the same state-preservation, Arrange, text-edit, context, screenshot, HMR, and completion rules described here.
|
|
47
47
|
|
|
48
48
|
## Reuse a live human instance
|
|
49
49
|
|
|
@@ -60,7 +60,7 @@ if (hasMesurer) {
|
|
|
60
60
|
}
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
If Mesurer exists, use that exact instance. The person may already have arranged elements, selected targets, placed guides, measured gaps, held distances, enabled rulers/X-ray, saved annotations, or kept a screenshot preview open. That state is part of the user's visual message.
|
|
63
|
+
If Mesurer exists, use that exact instance. The person may already have arranged elements, edited copy/typography into a Desired state, selected targets, placed guides, measured gaps, held distances, enabled rulers/X-ray, saved annotations, or kept a screenshot preview open. That state is part of the user's visual message.
|
|
64
64
|
|
|
65
65
|
The injector reuses a live injected instance by default. Deliberate destructive replacement requires:
|
|
66
66
|
|
|
@@ -121,9 +121,24 @@ select
|
|
|
121
121
|
annotations
|
|
122
122
|
review
|
|
123
123
|
capturePlan
|
|
124
|
+
textEdits
|
|
125
|
+
textEdit
|
|
124
126
|
```
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
Direct text editing reports:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
textEdit
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
and exposes:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
textEdits()
|
|
138
|
+
textEdit(id)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
When `arrangePlugin()` is mounted, capabilities also reports:
|
|
127
142
|
|
|
128
143
|
```text
|
|
129
144
|
arrange
|
|
@@ -143,7 +158,7 @@ There is no `send`, `screenshots`, or `sendContext` delivery capability. Screens
|
|
|
143
158
|
|
|
144
159
|
## Broad Mesurer/context requests mean inspect all human intent
|
|
145
160
|
|
|
146
|
-
If the user says “check Mesurer,” “check Measure,” “look at Mesurer context,” “see what I highlighted/moved/annotated,” or otherwise asks generally about Mesurer state, treat that as a request to inspect the **combined live review state**, not only the return value of `context()`.
|
|
161
|
+
If the user says “check Mesurer,” “check Measure,” “look at Mesurer context,” “see what I highlighted/moved/annotated/edited,” or otherwise asks generally about Mesurer state, treat that as a request to inspect the **combined live review state**, not only the return value of `context()`.
|
|
147
162
|
|
|
148
163
|
Start with a non-destructive inventory:
|
|
149
164
|
|
|
@@ -154,6 +169,9 @@ const annotations = await window.__MESURER__.annotations()
|
|
|
154
169
|
const arrangements = capabilities.arrange
|
|
155
170
|
? await window.__MESURER__.arrangements()
|
|
156
171
|
: []
|
|
172
|
+
const textEdits = capabilities.textEdit
|
|
173
|
+
? await window.__MESURER__.textEdits()
|
|
174
|
+
: []
|
|
157
175
|
|
|
158
176
|
let selection = null
|
|
159
177
|
try {
|
|
@@ -173,13 +191,17 @@ const annotationContexts = await Promise.all(
|
|
|
173
191
|
const arrangeIntents = await Promise.all(
|
|
174
192
|
arrangements.map((intent) => window.__MESURER__.arrange(intent.id)),
|
|
175
193
|
)
|
|
194
|
+
|
|
195
|
+
const textEditIntents = await Promise.all(
|
|
196
|
+
textEdits.map((intent) => window.__MESURER__.textEdit(intent.id)),
|
|
197
|
+
)
|
|
176
198
|
```
|
|
177
199
|
|
|
178
|
-
Bring the useful pieces together before editing: target-bound notes, current selection, Arrange Before/Desired geometry, guides, measurements, held distances, exact target inspection, layout/style data, rulers/X-ray state, and any existing human screenshot preview that must be preserved.
|
|
200
|
+
Bring the useful pieces together before editing: target-bound notes, current selection, Arrange Before/Desired geometry, text Before/Desired copy and style deltas, guides, measurements, held distances, exact target inspection, layout/style data, rulers/X-ray state, and any existing human screenshot preview that must be preserved.
|
|
179
201
|
|
|
180
|
-
The user may have selected one element, annotated another, moved a group with Arrange, and left measurements/guides that explain the relationship. Those are not separate conversations. They are one encoded visual request. Do not ask the person to repeat information Mesurer already contains, and do not overwrite one channel before reading the others.
|
|
202
|
+
The user may have selected one element, annotated another, moved a group with Arrange, edited copy or typography, and left measurements/guides that explain the relationship. Those are not separate conversations. They are one encoded visual request. Do not ask the person to repeat information Mesurer already contains, and do not overwrite one channel before reading the others.
|
|
181
203
|
|
|
182
|
-
## Arrange has
|
|
204
|
+
## Arrange has high human-intent precedence
|
|
183
205
|
|
|
184
206
|
Arrange lets a person reposition selected rendered elements into the layout they want without editing application source. If Arrange is available, consume relevant saved intents before changing human selection or editing source:
|
|
185
207
|
|
|
@@ -248,9 +270,98 @@ matched ✓
|
|
|
248
270
|
|
|
249
271
|
If review is still numerically wrong, continue editing. If it is `stale` or `partial`, do not silently bind the intent to a different element.
|
|
250
272
|
|
|
251
|
-
##
|
|
273
|
+
## Direct text editing: human UI and durable intent
|
|
274
|
+
|
|
275
|
+
Direct text editing records human copy and typography intent without pretending to edit application source. It is not a separate top-level text-edit tool/plugin.
|
|
276
|
+
|
|
277
|
+
The human-facing inspection tool is **Typography**. The existing internal compatibility id and stable command remain `text-inspector` / `builtin.text-inspector`; agents should not script the toolbar by label.
|
|
278
|
+
|
|
279
|
+
A person enters direct editing while **Select** or **Typography** is active:
|
|
280
|
+
|
|
281
|
+
```text
|
|
282
|
+
double-click ordinary direct text
|
|
283
|
+
(or double-tap with touch/pen)
|
|
284
|
+
↓
|
|
285
|
+
current text is selected in full
|
|
286
|
+
↓
|
|
287
|
+
in-place editor uses rendered typography
|
|
288
|
+
↓
|
|
289
|
+
Mesurer-style direct typography toolbar
|
|
290
|
+
B / I / U / Font / Size / Weight / Color
|
|
291
|
+
+ separate semantic Text/H1/H2/H3 preset popup
|
|
292
|
+
+ contextual Typography card for that exact field
|
|
293
|
+
↓
|
|
294
|
+
Enter keeps Desired / Shift+Enter newline
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Because Arrange keeps Select active, this same interaction works while Arrange remains selected. Starting the edit contextually activates Typography for the field while Select/Arrange remain active; it does not force the reviewer out of the layout workflow.
|
|
298
|
+
|
|
299
|
+
The typography surface deliberately separates direct properties from semantic meaning:
|
|
300
|
+
|
|
301
|
+
- Bold/Italic/Underline, Font, Size, Weight, rendered-page text colors, and custom color are direct toolbar controls;
|
|
302
|
+
- the separate semantic popup contains only **Text** plus Heading 1/2/3 for semantic levels actually rendered by visible direct-text page elements;
|
|
303
|
+
- each semantic preset uses the page's **dominant rendered typography bundle** for that level: font family, size, weight, style, line height, tracking, text transform, and color;
|
|
304
|
+
- non-dominant page variants remain available through the direct Font/Size/Weight/color controls;
|
|
305
|
+
- heading levels absent from the rendered page are not invented.
|
|
306
|
+
|
|
307
|
+
The semantic popup must not become a container for Font/Size/Weight/color. Its CSS chevron is part of the visual contract and rotates with popup state.
|
|
308
|
+
|
|
309
|
+
While the editor owns focus, `Cmd/Ctrl+B`, `Cmd/Ctrl+I`, and `Cmd/Ctrl+U` toggle formatting. Text/H1/H2/H3 use `Option+Cmd+0/1/2/3` on macOS and `Alt+Ctrl+0/1/2/3` elsewhere. If the semantic preset popup is open, the first Escape closes it; Escape with it closed cancels the edit.
|
|
252
310
|
|
|
253
|
-
|
|
311
|
+
Link creation and numbered/bulleted lists are intentionally not exposed as fake controls. Those would require a structural/rich-text intent model rather than ordinary typography deltas.
|
|
312
|
+
|
|
313
|
+
The contextual Typography card reuses the existing typography/card renderer and reports Family, Size, Weight, Line, Tracking, tag/text information, and CSS-variable references when available. It refreshes during the session. The current editing boundary is intentionally direct text rather than generic rich text: ordinary elements with one unambiguous non-empty direct text node. Native `<input>`, `<textarea>`, `<select>`, `contenteditable`, and ambiguous mixed/nested rich-text structures retain their normal browser/application behavior.
|
|
314
|
+
|
|
315
|
+
The contextual Typography card is **transient human presentation**, not another durable context channel. Durable intent is the saved text-edit record.
|
|
316
|
+
|
|
317
|
+
See the repository's canonical [`docs/TEXT_EDITING.md`](https://github.com/jhomra21/mesurer-solid/blob/main/docs/TEXT_EDITING.md) for the full interaction and runtime contract.
|
|
318
|
+
|
|
319
|
+
## Text/style Desired edits are source intent too
|
|
320
|
+
|
|
321
|
+
If `capabilities.textEdit` is true, read saved edits before source changes:
|
|
322
|
+
|
|
323
|
+
```js
|
|
324
|
+
const edits = await window.__MESURER__.textEdits()
|
|
325
|
+
const intent = await window.__MESURER__.textEdit(textEditId)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Each intent contains:
|
|
329
|
+
|
|
330
|
+
```text
|
|
331
|
+
id / createdAt / pageUrl
|
|
332
|
+
selector / nodeIndex
|
|
333
|
+
before
|
|
334
|
+
original text
|
|
335
|
+
desired
|
|
336
|
+
requested text
|
|
337
|
+
styles[]
|
|
338
|
+
property
|
|
339
|
+
before
|
|
340
|
+
desired
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Current style deltas can include font family, size, weight, style, line height, letter spacing, text transform, color, and text-decoration line.
|
|
344
|
+
|
|
345
|
+
Treat Desired copy and style deltas as a **visual/source specification**, not a request to paste Mesurer's preview implementation into production. If the person chose a semantic preset or a font, weight, size, or color that already exists on the rendered page, inspect the codebase for the semantic component prop, class, CSS variable, design token, theme value, or stylesheet rule that produces it.
|
|
346
|
+
|
|
347
|
+
Page-derived options are evidence of what the application already renders; they are not a source-code token scanner and do not imply that sampled computed values belong in inline styles.
|
|
348
|
+
|
|
349
|
+
While Select or Typography is active, Mesurer may be rendering the saved Desired text/style as a reversible preview. Do not compare against that preview and declare the source implementation correct.
|
|
350
|
+
|
|
351
|
+
After editing source:
|
|
352
|
+
|
|
353
|
+
1. retain the text-edit intent;
|
|
354
|
+
2. wait for the real render;
|
|
355
|
+
3. deactivate the active Select/Typography preview without clearing the intent;
|
|
356
|
+
4. inspect the actual target text and computed typography;
|
|
357
|
+
5. compare those Live values with `intent.desired` and `intent.styles`;
|
|
358
|
+
6. reactivate Select only if continued review is useful.
|
|
359
|
+
|
|
360
|
+
Mesurer relinquishes ownership when the application itself changes the value, so correct source output remains correct with the temporary preview inactive.
|
|
361
|
+
|
|
362
|
+
## Context acquisition after intent preservation
|
|
363
|
+
|
|
364
|
+
Once any relevant Arrange and text-edit intent is retained, use this order for ordinary context.
|
|
254
365
|
|
|
255
366
|
### Existing human selection or annotation
|
|
256
367
|
|
|
@@ -366,6 +477,15 @@ await window.__MESURER__.showArrange(arrangeId, "live")
|
|
|
366
477
|
const review = await window.__MESURER__.reviewArrange(arrangeId)
|
|
367
478
|
```
|
|
368
479
|
|
|
480
|
+
Text/style Desired intent, with its temporary preview inactive:
|
|
481
|
+
|
|
482
|
+
```js
|
|
483
|
+
const intent = await window.__MESURER__.textEdit(textEditId)
|
|
484
|
+
const live = window.__MESURER__.inspect(intent.selector)
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Compare the actual rendered text and relevant typography values with the saved Desired intent.
|
|
488
|
+
|
|
369
489
|
Annotation:
|
|
370
490
|
|
|
371
491
|
```js
|
|
@@ -423,12 +543,13 @@ try {
|
|
|
423
543
|
}
|
|
424
544
|
```
|
|
425
545
|
|
|
426
|
-
Arrange uses the same ownership model through `arrangeCapturePlan()` while adding explicit Before/Desired/Live presentation.
|
|
546
|
+
Active direct-editor controls, the semantic preset popup, and the contextual Typography card are Mesurer chrome, not application evidence. Arrange uses the same screenshot ownership model through `arrangeCapturePlan()` while adding explicit Before/Desired/Live presentation.
|
|
427
547
|
|
|
428
|
-
Use
|
|
548
|
+
Use all three signals when relevant:
|
|
429
549
|
|
|
430
550
|
```text
|
|
431
551
|
Mesurer context/review → geometry, box model, styles, distances, overflow
|
|
552
|
+
saved Desired intent → requested Arrange geometry + copy/typography
|
|
432
553
|
real screenshot → composition, hierarchy, clipping, color, visual judgment
|
|
433
554
|
```
|
|
434
555
|
|
|
@@ -454,7 +575,7 @@ const mesurer = mountMesurer({
|
|
|
454
575
|
|
|
455
576
|
The same API is available on `mesurer.agent` and, when configured, `window.__MESURER__`.
|
|
456
577
|
|
|
457
|
-
Arrange remains optional.
|
|
578
|
+
Arrange remains optional. Direct text editing and text-edit intent are part of the base inspector runtime; applications do not need a separate text-edit plugin.
|
|
458
579
|
|
|
459
580
|
## Low-level inspection
|
|
460
581
|
|
|
@@ -468,10 +589,12 @@ window.__MESURER__.distance(".a", ".b")
|
|
|
468
589
|
window.__MESURER__.viewport()
|
|
469
590
|
await window.__MESURER__.feedback([".selector"])
|
|
470
591
|
await window.__MESURER__.state()
|
|
592
|
+
await window.__MESURER__.textEdits()
|
|
593
|
+
await window.__MESURER__.textEdit(textEditId)
|
|
471
594
|
await window.__MESURER__.stable()
|
|
472
595
|
```
|
|
473
596
|
|
|
474
|
-
Prefer `arrangements()`, `context()`, `select()`, `reviewArrange()`, and `review()` for visual development because those paths preserve human meaning and return evidence the agent can reason from directly.
|
|
597
|
+
Prefer `arrangements()`, `textEdits()`, `context()`, `select()`, `reviewArrange()`, and `review()` for visual development because those paths preserve human meaning and return evidence the agent can reason from directly.
|
|
475
598
|
|
|
476
599
|
## Completion rule
|
|
477
600
|
|
|
@@ -479,18 +602,18 @@ A good harness-level loop is:
|
|
|
479
602
|
|
|
480
603
|
```text
|
|
481
604
|
1. discover/reuse Mesurer and preserve human state
|
|
482
|
-
2. if the request is broad, inventory Arrange + annotations + selection + workspace context before narrowing
|
|
483
|
-
3. consume relevant Arrange intent first
|
|
484
|
-
4. capture Before/Desired when useful, before source edits
|
|
605
|
+
2. if the request is broad, inventory Arrange + text edits + annotations + selection + workspace context before narrowing
|
|
606
|
+
3. consume relevant Arrange and text/style Desired intent first
|
|
607
|
+
4. capture Arrange Before/Desired when useful, before source edits
|
|
485
608
|
5. consume existing annotation/selection context
|
|
486
609
|
6. resolve exact targets; ask only when genuinely ambiguous
|
|
487
610
|
7. edit normal source
|
|
488
611
|
8. wait for stable render
|
|
489
|
-
9. switch Arrange to Live when applicable
|
|
490
|
-
10. get fresh
|
|
612
|
+
9. switch Arrange to Live and deactivate text Desired preview when applicable
|
|
613
|
+
10. get fresh source-rendered review/context and optional screenshot
|
|
491
614
|
11. iterate until rendered evidence supports completion
|
|
492
615
|
```
|
|
493
616
|
|
|
494
|
-
Do not clear Arrange history, alter human measurements/guides, replace live Mesurer state, or use a temporary preview to make unfinished source work appear correct.
|
|
617
|
+
Do not clear Arrange history, clear text-edit history just to reveal Live, alter human measurements/guides, replace live Mesurer state, or use a temporary preview to make unfinished source work appear correct.
|
|
495
618
|
|
|
496
|
-
**Rendered evidence is the output of the Mesurer step, not an optional side effect.**
|
|
619
|
+
**Rendered evidence is the output of the Mesurer step, not an optional side effect.**
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mesurer-solid
|
|
2
2
|
|
|
3
|
-
Framework-agnostic UI measurement, visual inspection, layout intent, and agent-ready rendered context for browser applications.
|
|
3
|
+
Framework-agnostic UI measurement, visual inspection, layout intent, direct text editing, 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
|
|
|
@@ -45,13 +45,13 @@ import { createRoot } from "react-dom/client"
|
|
|
45
45
|
import { mountMesurer } from "mesurer-solid"
|
|
46
46
|
import { App } from "./App"
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
: undefined
|
|
48
|
+
if (import.meta.env.DEV) {
|
|
49
|
+
const mesurer = mountMesurer()
|
|
51
50
|
|
|
52
|
-
import.meta.hot
|
|
53
|
-
|
|
54
|
-
}
|
|
51
|
+
if (import.meta.hot) {
|
|
52
|
+
import.meta.hot.dispose(() => mesurer.dispose())
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
55
|
|
|
56
56
|
createRoot(document.getElementById("root")!).render(<App />)
|
|
57
57
|
```
|
|
@@ -63,13 +63,13 @@ import { render } from "solid-js/web"
|
|
|
63
63
|
import { mountMesurer } from "mesurer-solid"
|
|
64
64
|
import App from "./App"
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
: undefined
|
|
66
|
+
if (import.meta.env.DEV) {
|
|
67
|
+
const mesurer = mountMesurer()
|
|
69
68
|
|
|
70
|
-
import.meta.hot
|
|
71
|
-
|
|
72
|
-
}
|
|
69
|
+
if (import.meta.hot) {
|
|
70
|
+
import.meta.hot.dispose(() => mesurer.dispose())
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
73
|
|
|
74
74
|
render(() => <App />, document.getElementById("root")!)
|
|
75
75
|
```
|
|
@@ -79,13 +79,13 @@ For Vue, Svelte, or vanilla Vite, put the same Mesurer block in the existing `sr
|
|
|
79
79
|
```ts
|
|
80
80
|
import { mountMesurer } from "mesurer-solid"
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
: undefined
|
|
82
|
+
if (import.meta.env.DEV) {
|
|
83
|
+
const mesurer = mountMesurer()
|
|
85
84
|
|
|
86
|
-
import.meta.hot
|
|
87
|
-
|
|
88
|
-
}
|
|
85
|
+
if (import.meta.hot) {
|
|
86
|
+
import.meta.hot.dispose(() => mesurer.dispose())
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
89
|
|
|
90
90
|
// Keep the app's existing browser startup code here as usual.
|
|
91
91
|
```
|
|
@@ -96,13 +96,13 @@ For Electron, use the renderer entry—not the Electron main process:
|
|
|
96
96
|
// src/renderer.ts
|
|
97
97
|
import { mountMesurer } from "mesurer-solid"
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
: undefined
|
|
99
|
+
if (import.meta.env.DEV) {
|
|
100
|
+
const mesurer = mountMesurer()
|
|
102
101
|
|
|
103
|
-
import.meta.hot
|
|
104
|
-
|
|
105
|
-
}
|
|
102
|
+
if (import.meta.hot) {
|
|
103
|
+
import.meta.hot.dispose(() => mesurer.dispose())
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
106
|
|
|
107
107
|
// Existing renderer startup follows.
|
|
108
108
|
```
|
|
@@ -129,9 +129,9 @@ import { mountMesurer } from "mesurer-solid"
|
|
|
129
129
|
|
|
130
130
|
const mesurer = mountMesurer()
|
|
131
131
|
|
|
132
|
-
import.meta.hot
|
|
133
|
-
mesurer.dispose()
|
|
134
|
-
}
|
|
132
|
+
if (import.meta.hot) {
|
|
133
|
+
import.meta.hot.dispose(() => mesurer.dispose())
|
|
134
|
+
}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
Then load that helper from the same existing browser entry:
|
|
@@ -156,9 +156,9 @@ import { mountMesurer } from "mesurer-solid"
|
|
|
156
156
|
const mesurer = mountMesurer()
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
The base inspector includes Select, X-ray, Rulers,
|
|
159
|
+
The base inspector includes Select, X-ray, Rulers, **Typography**, Guides, Distance, Settings, the plugin host, and the low-level inspection API. Color Picker is also available when the host exposes an operational native `EyeDropper`; it is intentionally hidden in unsupported hosts and has no DOM/CSS fallback.
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
Typography inspects rendered type and uses shortcut `A`. The internal built-in id remains `text-inspector` for compatibility. Direct text editing is also available while Select is active, including the Select state used by Arrange.
|
|
162
162
|
|
|
163
163
|
### Keyboard shortcuts
|
|
164
164
|
|
|
@@ -169,7 +169,7 @@ Text Inspector can inspect rendered typography and supports reversible Desired-t
|
|
|
169
169
|
| `X` | X-ray |
|
|
170
170
|
| `P` | Native Color Picker when supported |
|
|
171
171
|
| `R` | Rulers |
|
|
172
|
-
| `A` |
|
|
172
|
+
| `A` | Typography |
|
|
173
173
|
| `G` | Guides |
|
|
174
174
|
| `H` / `V` | Choose horizontal / vertical guide orientation |
|
|
175
175
|
| `Alt` / `Option` | Distance overlay |
|
|
@@ -182,6 +182,46 @@ Text Inspector can inspect rendered typography and supports reversible Desired-t
|
|
|
182
182
|
|
|
183
183
|
In the current Codex browser host, Color Picker is not advertised and `P` is inert because native screen sampling is not operational there.
|
|
184
184
|
|
|
185
|
+
## Direct text and typography editing
|
|
186
|
+
|
|
187
|
+
With **Select** or **Typography** active, double-click direct text on desktop or double-tap with touch/pen. Mesurer opens an editor over the rendered target, matches the target's current typography, and selects the complete current text so typing replaces it immediately.
|
|
188
|
+
|
|
189
|
+
Because Arrange keeps Select active, the same workflow works while arranging: move a selected element, double-click its text, edit/style it, and continue arranging.
|
|
190
|
+
|
|
191
|
+
Opening the editor contextually activates **Typography for that exact field**. The Typography toolbar control becomes visibly active, and the live information card reports Family, Size, Weight, Line, Tracking, target/text information, and CSS-variable references when available. This contextual activation does not switch the page-targeting mode away from Select, so Arrange remains active. The contextual Typography state clears with the edit session unless Typography itself was explicitly selected.
|
|
192
|
+
|
|
193
|
+
The floating formatting strip uses the same white toolbar language as the main Mesurer toolbar. Frequent typography controls remain directly available: **B / I / U**, page-derived **Font / Size / Weight**, common rendered-page text colors, a custom color control, and a separate semantic **Text / Heading** preset control.
|
|
194
|
+
|
|
195
|
+
The semantic popup contains only page-derived presets:
|
|
196
|
+
|
|
197
|
+
- **Text**;
|
|
198
|
+
- **Heading 1** only when the page renders a visible direct-text H1;
|
|
199
|
+
- **Heading 2** only when the page renders a visible direct-text H2;
|
|
200
|
+
- **Heading 3** only when the page renders a visible direct-text H3.
|
|
201
|
+
|
|
202
|
+
Each preset uses the **dominant rendered typography bundle** for that semantic level. The bundle includes font family, size, weight, style, line height, tracking, text transform, and color. Mesurer does not invent heading levels that are not actually present.
|
|
203
|
+
|
|
204
|
+
Pages may contain several visual variants of the same semantic heading/body style. Those non-dominant variants remain directly available through Font, Size, Weight, and Color rather than being mixed into the semantic popup. A divider separates direct properties from the semantic preset control, whose fixed-geometry chevron avoids font-baseline alignment problems.
|
|
205
|
+
|
|
206
|
+
While the editor owns focus, `Cmd/Ctrl+B`, `Cmd/Ctrl+I`, and `Cmd/Ctrl+U` toggle Bold/Italic/Underline. Text/H1/H2/H3 presets expose `Option+Cmd+0/1/2/3` on macOS and `Alt+Ctrl+0/1/2/3` elsewhere; unavailable heading levels do nothing rather than creating an invented style.
|
|
207
|
+
|
|
208
|
+
The page-derived lists use computed styles from actual rendered text, not built-in Mesurer font/color presets. Mesurer live-previews the requested copy and styles on the target. Press **Enter** to keep the Desired edit or **Shift+Enter** to insert a newline. If the semantic preset popup is open, **Escape** closes that popup first; pressing Escape again cancels the editing session. Clicking outside the active editor/formatting surfaces commits it.
|
|
209
|
+
|
|
210
|
+
Saved text/style changes remain reversible Mesurer intent and participate in history. They do not write application source.
|
|
211
|
+
|
|
212
|
+
The current contract is deliberately direct-text editing rather than a generic rich-text engine. Mesurer targets ordinary elements with one unambiguous non-empty direct text node. Native `<input>`, `<textarea>`, `<select>`, and `contenteditable` controls keep their normal browser/application editing behavior, and mixed/nested rich-text structures are not silently flattened into this workflow. Link creation and numbered/bulleted lists are intentionally not exposed until there is a real structural/rich-text intent model for them.
|
|
213
|
+
|
|
214
|
+
When `agent: true` is enabled, the agent surface advertises `textEdit: true` and exposes saved intent directly:
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
const edits = await window.__MESURER__.textEdits()
|
|
218
|
+
const intent = await window.__MESURER__.textEdit(edits.at(-1).id)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The intent carries target identity, Before/Desired text, and requested style deltas. A coding agent should map those requests to the application's real component props, classes, CSS variables, design tokens, theme values, or stylesheets instead of copying temporary Mesurer preview styles blindly.
|
|
222
|
+
|
|
223
|
+
For the complete interaction, semantic preset rules, Before/Desired/Live semantics, target boundaries, automatic Typography behavior, agent verification workflow, and validation contract, see [`docs/TEXT_EDITING.md`](https://github.com/jhomra21/mesurer-solid/blob/main/docs/TEXT_EDITING.md).
|
|
224
|
+
|
|
185
225
|
## Arrange
|
|
186
226
|
|
|
187
227
|
Arrange is an optional first-party plugin for showing how selected rendered elements should be positioned without pretending to edit application source.
|
|
@@ -334,7 +374,7 @@ The current upstream audit and intentional differences are documented in [`docs/
|
|
|
334
374
|
The coding-agent contract is context-first and preserves existing human state:
|
|
335
375
|
|
|
336
376
|
```text
|
|
337
|
-
human Arrange / annotation / selection
|
|
377
|
+
human Arrange / text-style Desired edit / annotation / selection
|
|
338
378
|
→ window.__MESURER__
|
|
339
379
|
→ structured rendered evidence
|
|
340
380
|
→ source edit
|
|
@@ -357,7 +397,7 @@ if (hasMesurer) {
|
|
|
357
397
|
}
|
|
358
398
|
```
|
|
359
399
|
|
|
360
|
-
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.
|
|
400
|
+
A live human instance may already contain the information the agent needs. Do not overwrite selection, Arrange history, text-edit history, guides, measurements, annotations, or screenshot preview state before reading it.
|
|
361
401
|
|
|
362
402
|
Install the portable Agent Skill with:
|
|
363
403
|
|
|
@@ -433,6 +473,7 @@ Mesurer's renderer is bundled and isolated from the host framework. Supported ho
|
|
|
433
473
|
## More documentation
|
|
434
474
|
|
|
435
475
|
- [Getting started](https://github.com/jhomra21/mesurer-solid/blob/main/docs/GETTING_STARTED.md)
|
|
476
|
+
- [Direct text editing and Typography](https://github.com/jhomra21/mesurer-solid/blob/main/docs/TEXT_EDITING.md)
|
|
436
477
|
- [Arrange](https://github.com/jhomra21/mesurer-solid/blob/main/docs/ARRANGE.md)
|
|
437
478
|
- [Context workflow](https://github.com/jhomra21/mesurer-solid/blob/main/docs/CONTEXT_WORKFLOW.md)
|
|
438
479
|
- [Screenshots](https://github.com/jhomra21/mesurer-solid/blob/main/docs/SCREENSHOTS.md)
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import type { MesurerPluginDescription, MesurerPluginHost, PluginStateSnapshot } from "./core";
|
|
2
|
+
export declare const MESURER_TEXT_EDIT_SERVICE_ID = "text-edit";
|
|
3
|
+
export type MesurerTextStyleProperty = "font-family" | "font-size" | "font-weight" | "font-style" | "line-height" | "letter-spacing" | "text-transform" | "color" | "text-decoration-line";
|
|
4
|
+
export type MesurerTextStyleChange = {
|
|
5
|
+
property: MesurerTextStyleProperty;
|
|
6
|
+
before: string;
|
|
7
|
+
desired: string;
|
|
8
|
+
};
|
|
9
|
+
export type MesurerTextEditIntent = {
|
|
10
|
+
id: string;
|
|
11
|
+
createdAt: number;
|
|
12
|
+
pageUrl: string;
|
|
13
|
+
selector: string;
|
|
14
|
+
nodeIndex: number;
|
|
15
|
+
before: string;
|
|
16
|
+
desired: string;
|
|
17
|
+
styles: MesurerTextStyleChange[];
|
|
18
|
+
};
|
|
19
|
+
export type MesurerTextEditService = {
|
|
20
|
+
intents(): MesurerTextEditIntent[];
|
|
21
|
+
intent(id: string): MesurerTextEditIntent | null;
|
|
22
|
+
clear(): Promise<void>;
|
|
23
|
+
};
|
|
2
24
|
export type AgentRect = {
|
|
3
25
|
left: number;
|
|
4
26
|
top: number;
|
|
@@ -103,6 +125,8 @@ export type MesurerAgentHarness = {
|
|
|
103
125
|
feedback(selectors?: string[]): Promise<AgentFeedbackSnapshot>;
|
|
104
126
|
command(id: string, args?: AgentCommandArgs): Promise<void>;
|
|
105
127
|
state(): Promise<PluginStateSnapshot>;
|
|
128
|
+
textEdits(): Promise<MesurerTextEditIntent[]>;
|
|
129
|
+
textEdit(id: string): Promise<MesurerTextEditIntent>;
|
|
106
130
|
stable(frames?: number): Promise<void>;
|
|
107
131
|
};
|
|
108
132
|
export type CreateMesurerAgentHarnessOptions = {
|
package/dist/arrange.js
CHANGED
|
@@ -2900,7 +2900,7 @@ var Qn = "mesurer.arrange", $n = "arrange", er = "mesurer.arrange.intents", tr =
|
|
|
2900
2900
|
].join(",");
|
|
2901
2901
|
//#endregion
|
|
2902
2902
|
//#region src/version.ts
|
|
2903
|
-
var jr = "0.1.
|
|
2903
|
+
var jr = "0.1.6", Mr = tr, Nr = Qn, Pr = $n, Fr = nr, Ir = er, Lr = () => ({
|
|
2904
2904
|
...Ar(),
|
|
2905
2905
|
version: jr
|
|
2906
2906
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MesurerAgentHarness } from "./agent";
|
|
1
|
+
import { type MesurerAgentHarness, type MesurerTextEditIntent } from "./agent";
|
|
2
2
|
import type { ArrangeCapturePlan, ArrangeIntent, ArrangePresentation, ArrangeReview } from "./arrange";
|
|
3
3
|
import type { MesurerAnnotation, MesurerCapturePlanV1, MesurerContextRequest, MesurerContextV1, MesurerReviewV1 } from "./context";
|
|
4
4
|
import type { MesurerPlugin, MesurerPluginDescription, MesurerPluginHost } from "./core";
|
|
@@ -166,6 +166,7 @@ export type MesurerAgentCapabilities = {
|
|
|
166
166
|
review: boolean;
|
|
167
167
|
capturePlan: boolean;
|
|
168
168
|
arrange: boolean;
|
|
169
|
+
textEdit: boolean;
|
|
169
170
|
};
|
|
170
171
|
};
|
|
171
172
|
export type MesurerContextHarness = {
|
|
@@ -208,6 +209,8 @@ export type MountedMesurer = {
|
|
|
208
209
|
showArrange(id: string, state: ArrangePresentation): Promise<void>;
|
|
209
210
|
arrangeCapturePlan(id: string, state: ArrangePresentation): Promise<ArrangeCapturePlan>;
|
|
210
211
|
reviewArrange(id: string, tolerance?: number): Promise<ArrangeReview>;
|
|
212
|
+
textEdits(): Promise<MesurerTextEditIntent[]>;
|
|
213
|
+
textEdit(id: string): Promise<MesurerTextEditIntent>;
|
|
211
214
|
bringToFront(): void;
|
|
212
215
|
describe(): MesurerPluginDescription | undefined;
|
|
213
216
|
dispose(): void;
|
|
@@ -219,9 +222,9 @@ export type MountMeasurerOptions = MountMesurerOptions;
|
|
|
219
222
|
export type MountedMeasurer = MountedMesurer;
|
|
220
223
|
/** @deprecated Use `mountMesurer()`. */
|
|
221
224
|
export declare const mountMeasurer: typeof mountMesurer;
|
|
222
|
-
export { createMesurerAgentHarness } from "./agent";
|
|
225
|
+
export { createMesurerAgentHarness, MESURER_TEXT_EDIT_SERVICE_ID } from "./agent";
|
|
223
226
|
export { MESURER_VERSION } from "./version";
|
|
224
|
-
export type { AgentDistance, AgentEdges, AgentElementInspection, AgentFeedbackSnapshot, AgentRect, AgentViewportSnapshot, CreateMesurerAgentHarnessOptions, MesurerAgentHarness, } from "./agent";
|
|
227
|
+
export type { AgentDistance, AgentEdges, AgentElementInspection, AgentFeedbackSnapshot, AgentRect, AgentViewportSnapshot, CreateMesurerAgentHarnessOptions, MesurerAgentHarness, MesurerTextEditIntent, MesurerTextEditService, MesurerTextStyleChange, MesurerTextStyleProperty, } from "./agent";
|
|
225
228
|
export type { ArrangeCapturePlan, ArrangeIntent, ArrangeOffset, ArrangePresentation, ArrangeRect, ArrangeReview, ArrangeReviewTarget, ArrangeTarget, MesurerArrangeService, } from "./arrange";
|
|
226
229
|
export { captureMesurerContext, copyTextToClipboard, createMesurerCapturePlan, formatMesurerContext, reviewMesurerAnnotation, } from "./context";
|
|
227
230
|
export type { MesurerAnnotation, MesurerAnnotationBaseline, MesurerAnnotationTarget, MesurerCapturePlanV1, MesurerContextDistance, MesurerContextEdges, MesurerContextGuide, MesurerContextMeasurement, MesurerContextRect, MesurerContextRequest, MesurerContextTarget, MesurerContextV1, MesurerElementFingerprint, MesurerElementInspection, MesurerReviewChange, MesurerReviewMetricChange, MesurerReviewPresenceChange, MesurerReviewV1, } from "./context";
|