@1agh/maude 0.40.0 → 0.42.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 -44
- 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/_html-playwright.mjs +26 -4
- package/apps/studio/bin/_pdf-playwright.mjs +13 -2
- package/apps/studio/bin/_png-playwright.mjs +15 -2
- package/apps/studio/bin/_pptx-playwright.mjs +17 -4
- package/apps/studio/bin/_screenshot-playwright.mjs +17 -2
- package/apps/studio/bin/_svg-playwright.mjs +26 -4
- 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/screenshot.sh +53 -4
- 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 +1476 -76
- package/apps/studio/client/comments-overlay.css +130 -126
- package/apps/studio/client/export-center.jsx +426 -0
- package/apps/studio/client/github.js +8 -0
- package/apps/studio/client/styles/3-shell-maude.css +65 -0
- package/apps/studio/client/styles/4-components.css +150 -0
- package/apps/studio/comments-overlay.tsx +148 -41
- package/apps/studio/config.schema.json +2 -2
- 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 +19 -26
- package/apps/studio/exporters/_runtime.ts +104 -0
- package/apps/studio/exporters/html.ts +12 -20
- package/apps/studio/exporters/index.ts +14 -2
- package/apps/studio/exporters/jobs.ts +334 -0
- package/apps/studio/exporters/pdf.ts +16 -20
- package/apps/studio/exporters/png.ts +12 -20
- package/apps/studio/exporters/pptx.ts +22 -23
- package/apps/studio/exporters/scope.ts +1 -0
- package/apps/studio/exporters/svg.ts +14 -22
- package/apps/studio/exporters/video.ts +15 -17
- package/apps/studio/git/service.ts +3 -1
- package/apps/studio/history.ts +47 -1
- package/apps/studio/http.ts +368 -50
- 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/server.ts +3 -1
- 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 +24 -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/dns-rebinding-guard.test.ts +27 -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/export-center.test.tsx +287 -0
- package/apps/studio/test/export-shim-multi-capture.test.ts +83 -0
- package/apps/studio/test/exporters/history.test.ts +32 -3
- package/apps/studio/test/exporters/jobs.test.ts +263 -0
- 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 +45 -0
- package/apps/studio/ws.ts +6 -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/cli/lib/gitignore-block.mjs +1 -0
- package/package.json +8 -8
- package/plugins/design/dependencies.json +10 -2
|
@@ -16,7 +16,9 @@ import { useEffect, useRef, useState } from 'react';
|
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
IconChevronDown,
|
|
19
|
+
IconLetterA,
|
|
19
20
|
IconPresentation,
|
|
21
|
+
IconSquare,
|
|
20
22
|
SHAPE_KIND_ICONS,
|
|
21
23
|
TOOL_ICONS,
|
|
22
24
|
} from './canvas-icons.tsx';
|
|
@@ -214,6 +216,35 @@ const PALETTE_CSS = `
|
|
|
214
216
|
background: color-mix(in oklab, var(--maude-hud-accent, #d63b1f) 14%, transparent);
|
|
215
217
|
color: var(--maude-hud-accent, #d63b1f);
|
|
216
218
|
}
|
|
219
|
+
/* Stage I3 tail — "+ Element" insert popover. A vertical labeled list (not the
|
|
220
|
+
shape popover's icon grid): Div/Text/Image have no recognizable glyph on
|
|
221
|
+
their own, and this is a rare, must-be-legible action, not a recalled tool. */
|
|
222
|
+
.dc-tool-palette .dc-tp-insert { position: relative; display: inline-flex; }
|
|
223
|
+
.dc-tp-insert-popover {
|
|
224
|
+
position: absolute;
|
|
225
|
+
bottom: calc(100% + 8px);
|
|
226
|
+
left: 50%;
|
|
227
|
+
transform: translateX(-50%);
|
|
228
|
+
display: flex;
|
|
229
|
+
flex-direction: column;
|
|
230
|
+
gap: 2px;
|
|
231
|
+
padding: 4px;
|
|
232
|
+
min-width: 128px;
|
|
233
|
+
background: var(--maude-chrome-bg-0, #ffffff);
|
|
234
|
+
border: 1px solid var(--maude-chrome-fg-0, #1c1917);
|
|
235
|
+
border-radius: 8px;
|
|
236
|
+
box-shadow: 0 6px 24px var(--maude-chrome-shadow, color-mix(in oklab, #1c1917 10%, transparent));
|
|
237
|
+
z-index: 8;
|
|
238
|
+
}
|
|
239
|
+
.dc-tp-insert-popover button {
|
|
240
|
+
width: auto;
|
|
241
|
+
height: auto;
|
|
242
|
+
justify-content: flex-start;
|
|
243
|
+
gap: 8px;
|
|
244
|
+
padding: 6px 8px;
|
|
245
|
+
border-radius: 4px;
|
|
246
|
+
}
|
|
247
|
+
.dc-tp-insert-popover button span.dc-tp-insert-label { font-size: 12px; }
|
|
217
248
|
`.trim();
|
|
218
249
|
|
|
219
250
|
function ensurePaletteStyles(): void {
|
|
@@ -250,6 +281,34 @@ const SHAPE_KINDS: ReadonlyArray<{ kind: ShapeKind; label: string }> = [
|
|
|
250
281
|
{ kind: 'triangle-down', label: 'Triangle down' },
|
|
251
282
|
];
|
|
252
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Stage I3 tail — resolve the insert anchor for the tool-palette "+ Element"
|
|
286
|
+
* affordance's "or appends to the active artboard" mode (the plan's fallback
|
|
287
|
+
* when the user hasn't right-clicked a specific element). Growth-only: an
|
|
288
|
+
* artboard's `<article data-dc-screen>` carries NO `data-cd-id` of its own
|
|
289
|
+
* (`DCArtboard` doesn't forward it to the DOM — only its SOURCE JSX tag is
|
|
290
|
+
* stamped, unresolvable from here), so `applyInsertElement`'s `refId` can't
|
|
291
|
+
* target the artboard directly. Anchor on the artboard's LAST direct child
|
|
292
|
+
* that DOES carry a `data-cd-id` and insert `position:'after'` it — the exact
|
|
293
|
+
* relation the context-menu's element-relative insert already uses. Returns
|
|
294
|
+
* `null` for an empty (or artboard-less) canvas — a documented v1 limit; the
|
|
295
|
+
* per-element context-menu "Insert ▸ …" still works there once a first
|
|
296
|
+
* element exists. `doc` is injectable for testing without a real iframe.
|
|
297
|
+
*/
|
|
298
|
+
export function resolveInsertAnchor(
|
|
299
|
+
doc: Document = document
|
|
300
|
+
): { refId: string; position: 'after' } | null {
|
|
301
|
+
const current = doc.querySelector('[data-dc-screen][aria-current="true"]');
|
|
302
|
+
const artboardEl = current ?? doc.querySelector('[data-dc-screen]');
|
|
303
|
+
if (!artboardEl) return null;
|
|
304
|
+
const body = artboardEl.querySelector(':scope > .dc-artboard-body');
|
|
305
|
+
if (!body) return null;
|
|
306
|
+
const kids = Array.from(body.children).reverse();
|
|
307
|
+
const last = kids.find((el) => el.hasAttribute('data-cd-id'));
|
|
308
|
+
const refId = last?.getAttribute('data-cd-id');
|
|
309
|
+
return refId ? { refId, position: 'after' } : null;
|
|
310
|
+
}
|
|
311
|
+
|
|
253
312
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
254
313
|
// Component
|
|
255
314
|
|
|
@@ -259,19 +318,22 @@ export function ToolPalette() {
|
|
|
259
318
|
const chrome = useChromeVisibility();
|
|
260
319
|
const [mounted, setMounted] = useState(false);
|
|
261
320
|
const [shapeOpen, setShapeOpen] = useState(false);
|
|
321
|
+
const [insertOpen, setInsertOpen] = useState(false);
|
|
262
322
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
263
323
|
|
|
264
324
|
useEffect(() => setMounted(true), []);
|
|
265
325
|
useEffect(() => {
|
|
266
|
-
if (!shapeOpen) return;
|
|
326
|
+
if (!shapeOpen && !insertOpen) return;
|
|
267
327
|
const onDown = (e: PointerEvent) => {
|
|
268
328
|
if (!containerRef.current?.contains(e.target as Node)) {
|
|
269
329
|
setShapeOpen(false);
|
|
330
|
+
setInsertOpen(false);
|
|
270
331
|
}
|
|
271
332
|
};
|
|
272
333
|
const onKey = (e: KeyboardEvent) => {
|
|
273
334
|
if (e.key === 'Escape') {
|
|
274
335
|
setShapeOpen(false);
|
|
336
|
+
setInsertOpen(false);
|
|
275
337
|
}
|
|
276
338
|
};
|
|
277
339
|
document.addEventListener('pointerdown', onDown, true);
|
|
@@ -280,12 +342,38 @@ export function ToolPalette() {
|
|
|
280
342
|
document.removeEventListener('pointerdown', onDown, true);
|
|
281
343
|
document.removeEventListener('keydown', onKey, true);
|
|
282
344
|
};
|
|
283
|
-
}, [shapeOpen]);
|
|
345
|
+
}, [shapeOpen, insertOpen]);
|
|
284
346
|
// Close the shape popover whenever the tool changes away from Shape.
|
|
285
347
|
useEffect(() => {
|
|
286
348
|
if (tool !== 'shape') setShapeOpen(false);
|
|
287
349
|
}, [tool]);
|
|
288
350
|
|
|
351
|
+
// Stage I3 tail — insert a Div/Text/Image relative to the active artboard's
|
|
352
|
+
// last existing element (`resolveInsertAnchor`). Same request verbs the
|
|
353
|
+
// context-menu's per-element "Insert ▸ …" already posts (`insert-request` /
|
|
354
|
+
// `insert-image-request`, main-origin shell WRITES — DDR-054); a null anchor
|
|
355
|
+
// (empty/artboard-less canvas) is a silent no-op — a documented v1 limit.
|
|
356
|
+
const insertViaPalette = (kind: 'div' | 'text' | 'image') => {
|
|
357
|
+
setInsertOpen(false);
|
|
358
|
+
const anchor = resolveInsertAnchor();
|
|
359
|
+
if (!anchor) return;
|
|
360
|
+
try {
|
|
361
|
+
if (kind === 'image') {
|
|
362
|
+
window.parent.postMessage(
|
|
363
|
+
{ dgn: 'insert-image-request', refId: anchor.refId, position: anchor.position },
|
|
364
|
+
'*'
|
|
365
|
+
);
|
|
366
|
+
} else {
|
|
367
|
+
window.parent.postMessage(
|
|
368
|
+
{ dgn: 'insert-request', refId: anchor.refId, position: anchor.position, kind },
|
|
369
|
+
'*'
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
} catch {
|
|
373
|
+
/* detached / cross-origin teardown */
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
289
377
|
if (!mounted) return null;
|
|
290
378
|
// Presentation Mode hides the whole tool palette (clean artboards-only view).
|
|
291
379
|
if (chrome?.present) return null;
|
|
@@ -393,6 +481,38 @@ export function ToolPalette() {
|
|
|
393
481
|
</div>
|
|
394
482
|
<div className="dc-tp-sep" />
|
|
395
483
|
<div className="dc-tp-group">
|
|
484
|
+
<span className="dc-tp-insert">
|
|
485
|
+
<button
|
|
486
|
+
type="button"
|
|
487
|
+
aria-label="Insert element — Div, Text, or Image"
|
|
488
|
+
aria-haspopup="menu"
|
|
489
|
+
aria-expanded={insertOpen}
|
|
490
|
+
title="Insert element (appends to the active artboard)"
|
|
491
|
+
onClick={() => setInsertOpen((o) => !o)}
|
|
492
|
+
>
|
|
493
|
+
<span aria-hidden="true" style={{ fontSize: 16, lineHeight: 1 }}>
|
|
494
|
+
+
|
|
495
|
+
</span>
|
|
496
|
+
</button>
|
|
497
|
+
{insertOpen ? (
|
|
498
|
+
<div className="dc-tp-insert-popover" role="menu" aria-label="Insert element">
|
|
499
|
+
<button type="button" role="menuitem" onClick={() => insertViaPalette('div')}>
|
|
500
|
+
<IconSquare />
|
|
501
|
+
<span className="dc-tp-insert-label">Div</span>
|
|
502
|
+
</button>
|
|
503
|
+
<button type="button" role="menuitem" onClick={() => insertViaPalette('text')}>
|
|
504
|
+
<IconLetterA />
|
|
505
|
+
<span className="dc-tp-insert-label">Text</span>
|
|
506
|
+
</button>
|
|
507
|
+
<button type="button" role="menuitem" onClick={() => insertViaPalette('image')}>
|
|
508
|
+
<span aria-hidden="true" style={{ fontSize: 13, lineHeight: 1 }}>
|
|
509
|
+
▧
|
|
510
|
+
</span>
|
|
511
|
+
<span className="dc-tp-insert-label">Image</span>
|
|
512
|
+
</button>
|
|
513
|
+
</div>
|
|
514
|
+
) : null}
|
|
515
|
+
</span>
|
|
396
516
|
<button
|
|
397
517
|
type="button"
|
|
398
518
|
aria-label="Export (⌘E)"
|
package/apps/studio/undo-hud.tsx
CHANGED
|
@@ -32,12 +32,12 @@ const HUD_CSS = `
|
|
|
32
32
|
user-select: none;
|
|
33
33
|
opacity: 0;
|
|
34
34
|
transform: translateY(-4px);
|
|
35
|
-
transition: opacity
|
|
35
|
+
transition: opacity 200ms linear, transform 200ms ease-out;
|
|
36
36
|
}
|
|
37
37
|
.dc-undo-hud[data-visible="true"] {
|
|
38
38
|
opacity: 1;
|
|
39
39
|
transform: translateY(0);
|
|
40
|
-
transition-duration:
|
|
40
|
+
transition-duration: 120ms;
|
|
41
41
|
}
|
|
42
42
|
@media (prefers-reduced-motion: reduce) {
|
|
43
43
|
.dc-undo-hud {
|