@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.
Files changed (73) hide show
  1. package/apps/studio/ai-banner.tsx +2 -2
  2. package/apps/studio/annotations-layer.tsx +53 -2
  3. package/apps/studio/api.ts +504 -3
  4. package/apps/studio/artboard-marquee.tsx +1 -1
  5. package/apps/studio/bin/_canvas-rects-playwright.mjs +55 -0
  6. package/apps/studio/bin/_canvas-rects-static.mjs +166 -0
  7. package/apps/studio/bin/_fetch-asset.mjs +556 -0
  8. package/apps/studio/bin/annotate.mjs +576 -34
  9. package/apps/studio/bin/canvas-rects.sh +152 -0
  10. package/apps/studio/bin/fetch-asset.sh +34 -0
  11. package/apps/studio/bin/read-annotations.mjs +138 -7
  12. package/apps/studio/bin/smoke.sh +42 -6
  13. package/apps/studio/build.ts +21 -0
  14. package/apps/studio/canvas-comment-mount.tsx +138 -4
  15. package/apps/studio/canvas-edit.ts +744 -11
  16. package/apps/studio/canvas-lib.tsx +219 -2
  17. package/apps/studio/canvas-shell.tsx +487 -20
  18. package/apps/studio/client/app.jsx +1451 -22
  19. package/apps/studio/client/comments-overlay.css +130 -126
  20. package/apps/studio/client/github.js +8 -0
  21. package/apps/studio/client/styles/3-shell-maude.css +48 -0
  22. package/apps/studio/comments-overlay.tsx +148 -41
  23. package/apps/studio/context-menu.tsx +15 -5
  24. package/apps/studio/contextual-toolbar.tsx +262 -4
  25. package/apps/studio/cursors-overlay.tsx +4 -4
  26. package/apps/studio/dist/client.bundle.js +20 -20
  27. package/apps/studio/dist/comment-mount.js +59 -1
  28. package/apps/studio/dist/styles.css +1 -1
  29. package/apps/studio/dom-selection.ts +127 -1
  30. package/apps/studio/drag-state.ts +24 -0
  31. package/apps/studio/equal-spacing-detector.ts +205 -0
  32. package/apps/studio/export-dialog.tsx +1 -1
  33. package/apps/studio/history.ts +47 -1
  34. package/apps/studio/http.ts +223 -0
  35. package/apps/studio/input-router.tsx +12 -0
  36. package/apps/studio/marquee-overlay.tsx +1 -1
  37. package/apps/studio/measure-overlay.tsx +241 -0
  38. package/apps/studio/participants-chrome.tsx +3 -3
  39. package/apps/studio/sizing-mode.ts +117 -0
  40. package/apps/studio/spacing-handles.ts +166 -0
  41. package/apps/studio/test/annotate-write.test.ts +890 -0
  42. package/apps/studio/test/camera-reveal.test.tsx +173 -0
  43. package/apps/studio/test/canvas-edit.test.ts +50 -0
  44. package/apps/studio/test/canvas-origin-gate.test.ts +18 -0
  45. package/apps/studio/test/canvas-rects.test.ts +198 -0
  46. package/apps/studio/test/comments-overlay.test.ts +117 -0
  47. package/apps/studio/test/dom-selection.test.ts +130 -0
  48. package/apps/studio/test/edit-css-occurrence.test.ts +81 -0
  49. package/apps/studio/test/edit-scope-api.test.ts +115 -0
  50. package/apps/studio/test/element-resize.test.ts +136 -0
  51. package/apps/studio/test/element-structural-api.test.ts +360 -0
  52. package/apps/studio/test/element-structural-edit.test.ts +233 -0
  53. package/apps/studio/test/equal-spacing-detector.test.ts +165 -1
  54. package/apps/studio/test/history-rollback.test.ts +26 -0
  55. package/apps/studio/test/knob-props-authored.test.ts +87 -0
  56. package/apps/studio/test/read-annotations.test.ts +154 -0
  57. package/apps/studio/test/sizing-mode.test.ts +102 -0
  58. package/apps/studio/test/spacing-handles.test.ts +138 -0
  59. package/apps/studio/test/specimen-select.test.ts +88 -0
  60. package/apps/studio/test/tool-palette-insert-anchor.test.ts +84 -0
  61. package/apps/studio/test/undo-sequence-byte-compare.test.ts +211 -0
  62. package/apps/studio/tool-palette.tsx +122 -2
  63. package/apps/studio/undo-hud.tsx +2 -2
  64. package/apps/studio/use-element-resize.tsx +732 -0
  65. package/apps/studio/use-keyboard-discipline.tsx +205 -15
  66. package/apps/studio/use-selection-set.tsx +14 -0
  67. package/apps/studio/use-spacing-handles.tsx +388 -0
  68. package/apps/studio/whats-new.json +28 -0
  69. package/cli/commands/design.mjs +6 -1
  70. package/cli/commands/design.test.mjs +49 -1
  71. package/cli/lib/fetch-asset.test.mjs +213 -0
  72. package/package.json +8 -8
  73. package/plugins/design/dependencies.json +10 -2
@@ -43,9 +43,9 @@ const BANNER_CSS = `
43
43
  background: var(--maude-hud-accent-tint, oklch(92% 0.040 55));
44
44
  color: var(--maude-chrome-fg-0, #111);
45
45
  border: 1px solid var(--maude-chrome-border, rgba(0,0,0,0.16));
46
- border-radius: var(--radius-md, 4px);
46
+ border-radius: 4px;
47
47
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
48
- font-family: var(--font-sans, system-ui, -apple-system, sans-serif);
48
+ font-family: system-ui, -apple-system, sans-serif;
49
49
  font-weight: 500;
50
50
  font-size: 12px;
51
51
  line-height: 1.2;
@@ -1076,11 +1076,36 @@ export function AnnotationsLayer() {
1076
1076
  }
1077
1077
  if (m.dgn === 'annotation-select-all') {
1078
1078
  if (annotSel) annotSel.replace(strokes.map((s) => s.id));
1079
+ return;
1080
+ }
1081
+ // Stage F3 — the shell's AssetPicker (main-origin, DDR-054) resolved a new
1082
+ // asset for an ImageStroke/MediaRefStroke's "Replace…" context-menu entry;
1083
+ // the canvas iframe owns the annotation model, so the shell REQUESTS the
1084
+ // swap here rather than writing strokes itself. `href`/`src` mirrors each
1085
+ // stroke shape (ImageStroke.href / MediaRefStroke.src) — swap whichever key
1086
+ // the target stroke actually carries, everything else survives byte-for-byte.
1087
+ if (
1088
+ m.dgn === 'replace-annotation-media' &&
1089
+ typeof (m as { id?: unknown }).id === 'string' &&
1090
+ typeof (m as { path?: unknown }).path === 'string'
1091
+ ) {
1092
+ const id = (m as { id: string }).id;
1093
+ const path = (m as { path: string }).path;
1094
+ const before = strokesRef.current;
1095
+ const target = before.find((s) => s.id === id);
1096
+ if (!target || (target.tool !== 'image' && target.tool !== 'mediaref')) return;
1097
+ const after = before.map((s) => {
1098
+ if (s.id !== id) return s;
1099
+ return target.tool === 'image'
1100
+ ? ({ ...s, href: path } as ImageStroke)
1101
+ : ({ ...s, src: path } as MediaRefStroke);
1102
+ });
1103
+ commitStrokes(before, after, 'replace media');
1079
1104
  }
1080
1105
  };
1081
1106
  window.addEventListener('message', onMessage);
1082
1107
  return () => window.removeEventListener('message', onMessage);
1083
- }, [annotSel, strokes, setVisible]);
1108
+ }, [annotSel, strokes, setVisible, commitStrokes]);
1084
1109
 
1085
1110
  // Document-level toggle: Shift+P (presentation). Annotation-shortcut help is
1086
1111
  // owned by the dev-server menubar (Help button); we no longer ship an
@@ -2737,9 +2762,27 @@ export function AnnotationsLayer() {
2737
2762
  if (members) annotSel.replace(members);
2738
2763
  } else if (action === 'ungroup') {
2739
2764
  store.ungroupSelection(sel);
2765
+ } else if (action === 'replace') {
2766
+ // Stage F3 — "Replace…" on an ImageStroke/MediaRefStroke. The canvas
2767
+ // REQUESTS (untrusted-origin postMessage, DDR-054); the main-origin shell
2768
+ // opens the AssetPicker and posts the picked path back down (handled by
2769
+ // the `replace-annotation-media` listener above, which owns the write —
2770
+ // this model has no data-cd-id, so it can't ride edit-attr like F2).
2771
+ if (sel.length !== 1) return;
2772
+ const target = strokesById.get(sel[0] as string);
2773
+ if (!target || (target.tool !== 'image' && target.tool !== 'mediaref')) return;
2774
+ const before = target.tool === 'image' ? target.href : target.src;
2775
+ try {
2776
+ window.parent.postMessage(
2777
+ { dgn: 'replace-annotation-media-request', id: target.id, before },
2778
+ '*'
2779
+ );
2780
+ } catch {
2781
+ /* detached / cross-origin teardown */
2782
+ }
2740
2783
  }
2741
2784
  },
2742
- [annotSel, copySelection, pasteStrokesText]
2785
+ [annotSel, copySelection, pasteStrokesText, strokesById]
2743
2786
  );
2744
2787
 
2745
2788
  // FigJam v3 — first time a multi-selection lands, surface the group /
@@ -2816,6 +2859,10 @@ export function AnnotationsLayer() {
2816
2859
  pos={ctxMenu}
2817
2860
  selCount={annotSel.selectedIds.length}
2818
2861
  canUngroup={selectedStrokes.some((s) => (s.groupIds?.length ?? 0) > 0)}
2862
+ canReplace={
2863
+ selectedStrokes.length === 1 &&
2864
+ (selectedStrokes[0]?.tool === 'image' || selectedStrokes[0]?.tool === 'mediaref')
2865
+ }
2819
2866
  onAction={onMenuAction}
2820
2867
  onClose={() => setCtxMenu(null)}
2821
2868
  />
@@ -3750,12 +3797,15 @@ function AnnotationContextMenu({
3750
3797
  pos,
3751
3798
  selCount,
3752
3799
  canUngroup,
3800
+ canReplace,
3753
3801
  onAction,
3754
3802
  onClose,
3755
3803
  }: {
3756
3804
  pos: { x: number; y: number };
3757
3805
  selCount: number;
3758
3806
  canUngroup: boolean;
3807
+ /** Stage F3 — exactly one ImageStroke/MediaRefStroke is selected. */
3808
+ canReplace: boolean;
3759
3809
  onAction: (action: string) => void;
3760
3810
  onClose: () => void;
3761
3811
  }) {
@@ -3822,6 +3872,7 @@ function AnnotationContextMenu({
3822
3872
  {item('cut', 'Cut', '⌘X')}
3823
3873
  {item('paste', 'Paste', '⌘V')}
3824
3874
  {item('duplicate', 'Duplicate', '⌘D')}
3875
+ {canReplace ? item('replace', 'Replace…') : null}
3825
3876
  <div className="dc-menu-sep" aria-hidden="true" />
3826
3877
  {item('front', 'Bring to front', ']')}
3827
3878
  {item('forward', 'Bring forward', '⌘]')}