@1agh/maude 0.40.0 → 0.41.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/apps/studio/ai-banner.tsx +2 -2
- package/apps/studio/annotations-layer.tsx +53 -2
- package/apps/studio/api.ts +504 -3
- package/apps/studio/artboard-marquee.tsx +1 -1
- package/apps/studio/bin/_canvas-rects-playwright.mjs +55 -0
- package/apps/studio/bin/_canvas-rects-static.mjs +166 -0
- package/apps/studio/bin/_fetch-asset.mjs +556 -0
- package/apps/studio/bin/annotate.mjs +576 -34
- package/apps/studio/bin/canvas-rects.sh +152 -0
- package/apps/studio/bin/fetch-asset.sh +34 -0
- package/apps/studio/bin/read-annotations.mjs +138 -7
- package/apps/studio/bin/smoke.sh +42 -6
- package/apps/studio/build.ts +21 -0
- package/apps/studio/canvas-comment-mount.tsx +138 -4
- package/apps/studio/canvas-edit.ts +744 -11
- package/apps/studio/canvas-lib.tsx +219 -2
- package/apps/studio/canvas-shell.tsx +487 -20
- package/apps/studio/client/app.jsx +1451 -22
- package/apps/studio/client/comments-overlay.css +130 -126
- package/apps/studio/client/github.js +8 -0
- package/apps/studio/client/styles/3-shell-maude.css +48 -0
- package/apps/studio/comments-overlay.tsx +148 -41
- package/apps/studio/context-menu.tsx +15 -5
- package/apps/studio/contextual-toolbar.tsx +262 -4
- package/apps/studio/cursors-overlay.tsx +4 -4
- package/apps/studio/dist/client.bundle.js +20 -20
- package/apps/studio/dist/comment-mount.js +59 -1
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/dom-selection.ts +127 -1
- package/apps/studio/drag-state.ts +24 -0
- package/apps/studio/equal-spacing-detector.ts +205 -0
- package/apps/studio/export-dialog.tsx +1 -1
- package/apps/studio/history.ts +47 -1
- package/apps/studio/http.ts +223 -0
- package/apps/studio/input-router.tsx +12 -0
- package/apps/studio/marquee-overlay.tsx +1 -1
- package/apps/studio/measure-overlay.tsx +241 -0
- package/apps/studio/participants-chrome.tsx +3 -3
- package/apps/studio/sizing-mode.ts +117 -0
- package/apps/studio/spacing-handles.ts +166 -0
- package/apps/studio/test/annotate-write.test.ts +890 -0
- package/apps/studio/test/camera-reveal.test.tsx +173 -0
- package/apps/studio/test/canvas-edit.test.ts +50 -0
- package/apps/studio/test/canvas-origin-gate.test.ts +18 -0
- package/apps/studio/test/canvas-rects.test.ts +198 -0
- package/apps/studio/test/comments-overlay.test.ts +117 -0
- package/apps/studio/test/dom-selection.test.ts +130 -0
- package/apps/studio/test/edit-css-occurrence.test.ts +81 -0
- package/apps/studio/test/edit-scope-api.test.ts +115 -0
- package/apps/studio/test/element-resize.test.ts +136 -0
- package/apps/studio/test/element-structural-api.test.ts +360 -0
- package/apps/studio/test/element-structural-edit.test.ts +233 -0
- package/apps/studio/test/equal-spacing-detector.test.ts +165 -1
- package/apps/studio/test/history-rollback.test.ts +26 -0
- package/apps/studio/test/knob-props-authored.test.ts +87 -0
- package/apps/studio/test/read-annotations.test.ts +154 -0
- package/apps/studio/test/sizing-mode.test.ts +102 -0
- package/apps/studio/test/spacing-handles.test.ts +138 -0
- package/apps/studio/test/specimen-select.test.ts +88 -0
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +84 -0
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +211 -0
- package/apps/studio/tool-palette.tsx +122 -2
- package/apps/studio/undo-hud.tsx +2 -2
- package/apps/studio/use-element-resize.tsx +732 -0
- package/apps/studio/use-keyboard-discipline.tsx +205 -15
- package/apps/studio/use-selection-set.tsx +14 -0
- package/apps/studio/use-spacing-handles.tsx +388 -0
- package/apps/studio/whats-new.json +28 -0
- package/cli/commands/design.mjs +6 -1
- package/cli/commands/design.test.mjs +49 -1
- package/cli/lib/fetch-asset.test.mjs +213 -0
- package/package.json +8 -8
- package/plugins/design/dependencies.json +10 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file spacing-handles.ts — Stage J (feature-element-editing-robustness)
|
|
3
|
+
* @purpose Pure geometry + value math for the on-canvas padding + gap drag
|
|
4
|
+
* overlay. Framework-free (unit-testable without a DOM), mirroring
|
|
5
|
+
* `equal-spacing-detector.ts`'s screen-coordinate midpoint shape so
|
|
6
|
+
* the two spacing affordances (read-only equal-spacing dots vs this
|
|
7
|
+
* draggable padding/gap overlay) share a visual vocabulary.
|
|
8
|
+
*
|
|
9
|
+
* Padding: 4 edge lines inset from the element's screen border-box by
|
|
10
|
+
* its resolved padding × zoom, one per side, each carrying a drag axis
|
|
11
|
+
* (top/bottom = vertical, left/right = horizontal).
|
|
12
|
+
* Gap: midpoints between consecutive DIRECT children along the flex
|
|
13
|
+
* main axis (row → x, column → y) — flex-only in v1; CSS-Grid gap
|
|
14
|
+
* editing is deferred to `feature-grid-track-editor.md` (Stage M3).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface ScreenRect {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
w: number;
|
|
21
|
+
h: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type PaddingSide = 'top' | 'right' | 'bottom' | 'left';
|
|
25
|
+
|
|
26
|
+
export interface PaddingLine {
|
|
27
|
+
side: PaddingSide;
|
|
28
|
+
/** Drag axis: top/bottom edges scrub vertically, left/right horizontally. */
|
|
29
|
+
axis: 'x' | 'y';
|
|
30
|
+
/** Line midpoint in screen coords (the handle's paint position). */
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
/** Line length in screen px (spans the box's inner width/height on that side). */
|
|
34
|
+
length: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Compute the 4 padding-edge handle positions from the element's screen
|
|
39
|
+
* border-box rect + its resolved padding (WORLD px, pre-zoom) + the render
|
|
40
|
+
* zoom. A handle sits at the midpoint of its edge, INSET from the border by
|
|
41
|
+
* `padding × zoom` — i.e. right on the padding/content boundary, so dragging it
|
|
42
|
+
* outward (toward the border) shrinks padding, inward (toward center) grows it.
|
|
43
|
+
*/
|
|
44
|
+
export function computePaddingLines(
|
|
45
|
+
rect: ScreenRect,
|
|
46
|
+
padding: { top: number; right: number; bottom: number; left: number },
|
|
47
|
+
zoom: number
|
|
48
|
+
): PaddingLine[] {
|
|
49
|
+
const z = zoom > 0 ? zoom : 1;
|
|
50
|
+
const pt = padding.top * z;
|
|
51
|
+
const pr = padding.right * z;
|
|
52
|
+
const pb = padding.bottom * z;
|
|
53
|
+
const pl = padding.left * z;
|
|
54
|
+
return [
|
|
55
|
+
{ side: 'top', axis: 'y', x: rect.x + rect.w / 2, y: rect.y + pt, length: rect.w - pl - pr },
|
|
56
|
+
{
|
|
57
|
+
side: 'right',
|
|
58
|
+
axis: 'x',
|
|
59
|
+
x: rect.x + rect.w - pr,
|
|
60
|
+
y: rect.y + rect.h / 2,
|
|
61
|
+
length: rect.h - pt - pb,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
side: 'bottom',
|
|
65
|
+
axis: 'y',
|
|
66
|
+
x: rect.x + rect.w / 2,
|
|
67
|
+
y: rect.y + rect.h - pb,
|
|
68
|
+
length: rect.w - pl - pr,
|
|
69
|
+
},
|
|
70
|
+
{ side: 'left', axis: 'x', x: rect.x + pl, y: rect.y + rect.h / 2, length: rect.h - pt - pb },
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* New padding value (WORLD px, clamped ≥ 0) for a drag on `side`, given the
|
|
76
|
+
* screen-space cursor delta and the render zoom. Top/bottom respond to
|
|
77
|
+
* vertical delta, left/right to horizontal — and the SIGN flips for
|
|
78
|
+
* bottom/right (dragging toward the element's center — up for bottom, left for
|
|
79
|
+
* right — GROWS that side's padding, mirroring how top/left already grow when
|
|
80
|
+
* dragged down/right).
|
|
81
|
+
*/
|
|
82
|
+
export function computePaddingDrag(
|
|
83
|
+
side: PaddingSide,
|
|
84
|
+
startValue: number,
|
|
85
|
+
dxScreen: number,
|
|
86
|
+
dyScreen: number,
|
|
87
|
+
zoom: number
|
|
88
|
+
): number {
|
|
89
|
+
const z = zoom > 0 ? zoom : 1;
|
|
90
|
+
const d = side === 'top' || side === 'bottom' ? dyScreen / z : dxScreen / z;
|
|
91
|
+
const signed = side === 'bottom' || side === 'right' ? -d : d;
|
|
92
|
+
return Math.max(0, round2(startValue + signed));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type FlexAxis = 'x' | 'y';
|
|
96
|
+
|
|
97
|
+
/** Row/row-reverse → x (horizontal main axis); column/column-reverse → y. */
|
|
98
|
+
export function flexMainAxis(flexDirection: string | null | undefined): FlexAxis {
|
|
99
|
+
const dir = (flexDirection || 'row').trim();
|
|
100
|
+
return dir.startsWith('column') ? 'y' : 'x';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Midpoints between consecutive DIRECT children's screen rects, along `axis`.
|
|
105
|
+
* Mirrors `detectEqualSpacing`'s midpoint shape but needs no equal-spacing
|
|
106
|
+
* DETECTION (there's exactly one `gap` value to visualize, not several to
|
|
107
|
+
* confirm) — just the geometric midpoint of each adjacent pair's facing edges.
|
|
108
|
+
* Fewer than 2 children → no gaps to show.
|
|
109
|
+
*/
|
|
110
|
+
export function computeGapMidpoints(
|
|
111
|
+
childRects: ScreenRect[],
|
|
112
|
+
axis: FlexAxis
|
|
113
|
+
): Array<{ x: number; y: number }> {
|
|
114
|
+
if (childRects.length < 2) return [];
|
|
115
|
+
const sorted = [...childRects].sort((a, b) => (axis === 'x' ? a.x - b.x : a.y - b.y));
|
|
116
|
+
const out: Array<{ x: number; y: number }> = [];
|
|
117
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
118
|
+
const a = sorted[i] as ScreenRect;
|
|
119
|
+
const b = sorted[i + 1] as ScreenRect;
|
|
120
|
+
if (axis === 'x') {
|
|
121
|
+
out.push({ x: (a.x + a.w + b.x) / 2, y: a.y + a.h / 2 });
|
|
122
|
+
} else {
|
|
123
|
+
out.push({ x: a.x + a.w / 2, y: (a.y + a.h + b.y) / 2 });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** New `gap` value (WORLD px, clamped ≥ 0) for a drag along `axis`. Gap is a
|
|
130
|
+
* single shared CSS value, so every handle drags the SAME number 1:1 with the
|
|
131
|
+
* cursor (no doubling/halving — dragging a handle N screen px outward should
|
|
132
|
+
* feel like N world px of extra breathing room). */
|
|
133
|
+
export function computeGapDrag(
|
|
134
|
+
axis: FlexAxis,
|
|
135
|
+
startValue: number,
|
|
136
|
+
dxScreen: number,
|
|
137
|
+
dyScreen: number,
|
|
138
|
+
zoom: number
|
|
139
|
+
): number {
|
|
140
|
+
const z = zoom > 0 ? zoom : 1;
|
|
141
|
+
const d = axis === 'x' ? dxScreen / z : dyScreen / z;
|
|
142
|
+
return Math.max(0, round2(startValue + d));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function round2(n: number): number {
|
|
146
|
+
return Math.round(n * 100) / 100;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Which padding sides a drag on `side` touches, given the held modifiers —
|
|
151
|
+
* matches the CSS-panel box-model widget's OWN scrub grammar exactly (`side()`
|
|
152
|
+
* in `client/app.jsx`, `title="drag to scrub · alt = symmetric · alt+shift =
|
|
153
|
+
* all sides"`): plain drag = just this side; Alt = the symmetric axis PAIR
|
|
154
|
+
* (top+bottom, or left+right); Alt+Shift = all four. Every touched side is set
|
|
155
|
+
* to the SAME value (not each grown by its own delta) — same semantics as the
|
|
156
|
+
* panel's `sidesFor`/`last` write.
|
|
157
|
+
*/
|
|
158
|
+
export function paddingSideSet(
|
|
159
|
+
side: PaddingSide,
|
|
160
|
+
altKey: boolean,
|
|
161
|
+
shiftKey: boolean
|
|
162
|
+
): PaddingSide[] {
|
|
163
|
+
if (altKey && shiftKey) return ['top', 'right', 'bottom', 'left'];
|
|
164
|
+
if (altKey) return side === 'top' || side === 'bottom' ? ['top', 'bottom'] : ['left', 'right'];
|
|
165
|
+
return [side];
|
|
166
|
+
}
|