nudge-ui 0.2.1 → 0.2.3

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 (258) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +252 -54
  3. package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
  4. package/dist/css/value-semantics/colorSemantics.js +17 -0
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
  6. package/dist/hosts/astro/clientTransport.js +41 -32
  7. package/dist/hosts/astro/integration.d.ts +2 -2
  8. package/dist/hosts/astro/integration.js +9 -4
  9. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  10. package/dist/hosts/astro/markdownIdentity.js +81 -0
  11. package/dist/hosts/environment.d.ts +15 -0
  12. package/dist/hosts/environment.js +16 -0
  13. package/dist/hosts/next/manifest.js +1 -1
  14. package/dist/hosts/next/sidecar.js +12 -2
  15. package/dist/hosts/next/wrapper.d.ts +2 -0
  16. package/dist/hosts/next/wrapper.js +2 -1
  17. package/dist/hosts/projectBridge.d.ts +1 -0
  18. package/dist/hosts/projectBridge.js +1 -0
  19. package/dist/hosts/static/manifest.js +3 -1
  20. package/dist/hosts/static/server.js +4 -0
  21. package/dist/hosts/vite/vite.d.ts +4 -0
  22. package/dist/hosts/vite/vite.js +28 -5
  23. package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
  24. package/dist/inspector/agent/McpConnectionDialog.js +23 -22
  25. package/dist/inspector/agent/activity.d.ts +18 -0
  26. package/dist/inspector/agent/activity.js +70 -0
  27. package/dist/inspector/agent/client.d.ts +8 -0
  28. package/dist/inspector/agent/client.js +65 -5
  29. package/dist/inspector/agent/connectionStatus.d.ts +3 -3
  30. package/dist/inspector/agent/connectionStatus.js +9 -2
  31. package/dist/inspector/agent/httpTransport.d.ts +6 -0
  32. package/dist/inspector/agent/httpTransport.js +50 -3
  33. package/dist/inspector/agent/protocol.d.ts +9 -3
  34. package/dist/inspector/agent/protocol.js +1 -1
  35. package/dist/inspector/agent/verification.d.ts +11 -1
  36. package/dist/inspector/agent/verification.js +53 -25
  37. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  38. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  39. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  40. package/dist/inspector/canvas/CanvasCard.js +133 -38
  41. package/dist/inspector/canvas/CanvasElementOverlay.js +200 -22
  42. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  43. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  44. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  45. package/dist/inspector/canvas/CanvasWorkspace.js +243 -56
  46. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  47. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  48. package/dist/inspector/canvas/agentPresentation.js +64 -52
  49. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  50. package/dist/inspector/canvas/canvasGestures.js +1 -1
  51. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  52. package/dist/inspector/canvas/canvasStore.js +251 -284
  53. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  54. package/dist/inspector/canvas/frameContent.js +44 -0
  55. package/dist/inspector/canvas/frameProtocol.d.ts +34 -4
  56. package/dist/inspector/canvas/frameProtocol.js +9 -2
  57. package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
  58. package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
  59. package/dist/inspector/canvas/layout.d.ts +52 -0
  60. package/dist/inspector/canvas/layout.js +106 -0
  61. package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
  62. package/dist/inspector/canvas/linkEligibility.js +0 -29
  63. package/dist/inspector/canvas/projection.d.ts +15 -5
  64. package/dist/inspector/canvas/projection.js +69 -13
  65. package/dist/inspector/canvas/rendererBootstrap.js +45 -4
  66. package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
  67. package/dist/inspector/canvas/rendererElementSelector.js +102 -45
  68. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  69. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  70. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  71. package/dist/inspector/canvas/sessionStore.js +43 -183
  72. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  73. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  74. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  75. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  76. package/dist/inspector/canvas/viewStore.js +104 -0
  77. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  78. package/dist/inspector/canvas/wheelPan.js +8 -0
  79. package/dist/inspector/changes/changesLog.d.ts +6 -5
  80. package/dist/inspector/changes/changesLog.js +40 -32
  81. package/dist/inspector/changes/draftChanges.d.ts +56 -0
  82. package/dist/inspector/changes/draftChanges.js +300 -0
  83. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  84. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  85. package/dist/inspector/clientManifest.d.ts +3 -1
  86. package/dist/inspector/clientManifest.js +1 -0
  87. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  88. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  89. package/dist/inspector/comments/element.d.ts +6 -0
  90. package/dist/inspector/comments/element.js +47 -0
  91. package/dist/inspector/comments/store.d.ts +29 -0
  92. package/dist/inspector/comments/store.js +121 -0
  93. package/dist/inspector/comments/verification.d.ts +5 -0
  94. package/dist/inspector/comments/verification.js +52 -0
  95. package/dist/inspector/drafts/model.d.ts +35 -0
  96. package/dist/inspector/drafts/model.js +45 -0
  97. package/dist/inspector/drafts/store.d.ts +28 -0
  98. package/dist/inspector/drafts/store.js +231 -0
  99. package/dist/inspector/index.js +26 -35
  100. package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
  101. package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
  102. package/dist/inspector/iterations/capture.d.ts +2 -0
  103. package/dist/inspector/iterations/capture.js +173 -0
  104. package/dist/inspector/iterations/client.d.ts +7 -0
  105. package/dist/inspector/iterations/client.js +52 -0
  106. package/dist/inspector/iterations/coordinator.d.ts +15 -0
  107. package/dist/inspector/iterations/coordinator.js +130 -0
  108. package/dist/inspector/iterations/prompt.d.ts +3 -0
  109. package/dist/inspector/iterations/prompt.js +26 -0
  110. package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
  111. package/dist/inspector/overlay/DomNavigator.js +46 -0
  112. package/dist/inspector/overlay/InspectorOverlay.js +6 -2
  113. package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
  114. package/dist/inspector/overlay/clickPolicy.js +34 -3
  115. package/dist/inspector/overlay/elementSelector.d.ts +1 -1
  116. package/dist/inspector/overlay/elementSelector.js +18 -7
  117. package/dist/inspector/overlay/interactionStyles.js +3 -1
  118. package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
  119. package/dist/inspector/overlay/spacingGestures.js +88 -13
  120. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  121. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  122. package/dist/inspector/projection/renderedInstance.d.ts +2 -1
  123. package/dist/inspector/projection/renderedInstance.js +9 -5
  124. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  125. package/dist/inspector/projection/structuralProjection.js +19 -15
  126. package/dist/inspector/projection/textProjection.d.ts +2 -1
  127. package/dist/inspector/projection/textProjection.js +8 -4
  128. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  129. package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
  130. package/dist/inspector/prompt/clipboardHandoff.js +92 -143
  131. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  132. package/dist/inspector/prompt/generatePrompt.js +17 -16
  133. package/dist/inspector/runtime/runtimeConfig.d.ts +10 -1
  134. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  135. package/dist/inspector/selection/hierarchy.d.ts +6 -0
  136. package/dist/inspector/selection/hierarchy.js +8 -0
  137. package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
  138. package/dist/inspector/settings/SettingsDialog.js +22 -9
  139. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  140. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  141. package/dist/inspector/shell/AppShell.js +4 -2
  142. package/dist/inspector/shell/ChangesLog.js +47 -27
  143. package/dist/inspector/shell/CopyPromptButton.js +146 -90
  144. package/dist/inspector/shell/EmptyState.js +9 -8
  145. package/dist/inspector/shell/InspectorShell.js +14 -25
  146. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  147. package/dist/inspector/shell/originalPreview.js +5 -5
  148. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  149. package/dist/inspector/shell/shortcuts.js +11 -0
  150. package/dist/inspector/sketch/SketchEditor.js +14 -14
  151. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  152. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  153. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  154. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  155. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  156. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  157. package/dist/inspector/sketch/interaction.d.ts +1 -0
  158. package/dist/inspector/sketch/interaction.js +8 -4
  159. package/dist/inspector/sketch/model.d.ts +5 -0
  160. package/dist/inspector/sketch/model.js +6 -2
  161. package/dist/inspector/sketch/raster.d.ts +1 -2
  162. package/dist/inspector/sketch/raster.js +68 -4
  163. package/dist/inspector/sketch/store.js +48 -23
  164. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  165. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  166. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  167. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  168. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  169. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  170. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  171. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  172. package/dist/inspector/styleEditors/GapField.js +3 -5
  173. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  174. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  175. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  176. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  177. package/dist/inspector/styleEditors/GridSection.js +1 -1
  178. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  179. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  180. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  181. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  182. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  183. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  184. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  185. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  186. package/dist/inspector/styleEditors/SpacingBox.js +16 -9
  187. package/dist/inspector/styleEditors/Typography.js +11 -3
  188. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  189. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  190. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  191. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  192. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  193. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  194. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  195. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  196. package/dist/inspector/styleEditors/nudgeValue.d.ts +4 -4
  197. package/dist/inspector/styleEditors/nudgeValue.js +41 -11
  198. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  199. package/dist/inspector/tokens/TokenField.js +49 -22
  200. package/dist/inspector/tokens/TokenLabel.js +5 -14
  201. package/dist/inspector/tokens/TokensPanel.js +2 -1
  202. package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
  203. package/dist/inspector/tokens/dragPointerLock.js +70 -0
  204. package/dist/inspector/tokens/editActions.d.ts +1 -1
  205. package/dist/inspector/tokens/editActions.js +1 -1
  206. package/dist/inspector/ui/AtRuleContext.js +4 -6
  207. package/dist/inspector/ui/Button.d.ts +6 -2
  208. package/dist/inspector/ui/Button.js +4 -3
  209. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  210. package/dist/inspector/ui/ControlSurface.js +4 -3
  211. package/dist/inspector/ui/Disclosure.d.ts +22 -0
  212. package/dist/inspector/ui/Disclosure.js +13 -0
  213. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  214. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  215. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  216. package/dist/inspector/ui/InspectorPopover.js +4 -5
  217. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  218. package/dist/inspector/ui/PopoverListbox.js +8 -7
  219. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  220. package/dist/inspector/ui/SegmentedControl.js +2 -2
  221. package/dist/inspector/ui/Select.d.ts +6 -1
  222. package/dist/inspector/ui/Select.js +7 -11
  223. package/dist/inspector/ui/SideValuesField.js +1 -1
  224. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  225. package/dist/inspector/ui/Tooltip.js +32 -0
  226. package/dist/inspector/ui/classNames.d.ts +2 -0
  227. package/dist/inspector/ui/classNames.js +4 -0
  228. package/dist/inspector/ui/customCursors.d.ts +23 -0
  229. package/dist/inspector/ui/customCursors.js +122 -0
  230. package/dist/inspector/ui/dragCursor.d.ts +6 -0
  231. package/dist/inspector/ui/dragCursor.js +13 -0
  232. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  233. package/dist/inspector/ui/portalContainer.js +6 -0
  234. package/dist/inspector/ui/styles.js +34 -24
  235. package/dist/inspector/workspace/commands.d.ts +9 -0
  236. package/dist/inspector/workspace/commands.js +82 -0
  237. package/dist/inspector/workspace/controller.d.ts +4 -0
  238. package/dist/inspector/workspace/controller.js +66 -0
  239. package/dist/inspector/workspace/handoff.d.ts +42 -0
  240. package/dist/inspector/workspace/handoff.js +115 -0
  241. package/dist/inspector/workspace/timeline.d.ts +30 -0
  242. package/dist/inspector/workspace/timeline.js +108 -0
  243. package/dist/internal/agent-protocol.d.ts +19 -2
  244. package/dist/internal/agent-protocol.js +13 -0
  245. package/dist/nudge-ui.mjs +560 -299
  246. package/dist/project/artifacts.d.ts +13 -0
  247. package/dist/project/artifacts.js +253 -0
  248. package/dist/transport/artifacts.d.ts +8 -0
  249. package/dist/transport/artifacts.js +9 -0
  250. package/dist/transport/editor.d.ts +20 -1
  251. package/dist/transport/editor.js +44 -11
  252. package/dist/transport/routes.d.ts +6 -1
  253. package/dist/transport/routes.js +6 -1
  254. package/package.json +6 -2
  255. package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
  256. package/dist/inspector/changes/workspaceChanges.js +0 -239
  257. package/dist/inspector/shell/DomNavigation.d.ts +0 -8
  258. package/dist/inspector/shell/DomNavigation.js +0 -30
@@ -3,8 +3,8 @@ import { getOpen } from "../shell/openStore.js";
3
3
  import { resolveSelectionFromEvent } from "../selection/resolveSelection.js";
4
4
  import { handleInlineTextEditIntent, isInlineTextEditingActive, } from "../inline-text/inlineTextEditor.js";
5
5
  import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
6
- import { blockApplicationClick, isApplicationActivationClick } from "./clickPolicy.js";
7
- export function installElementSelector(inspectorHost) {
6
+ import { APPLICATION_GESTURE_EVENTS, blockApplicationClick, blockApplicationGesture, isInlineEditorTarget, isUserClick, } from "./clickPolicy.js";
7
+ export function installElementSelector(inspectorHost, acceptsClick = isUserClick) {
8
8
  function applyInlineTextDisposition(event, disposition) {
9
9
  if (disposition === "pass-through")
10
10
  return;
@@ -43,7 +43,7 @@ export function installElementSelector(inspectorHost) {
43
43
  return root instanceof ShadowRoot && root.host === inspectorHost;
44
44
  }
45
45
  function onClick(e) {
46
- if (!getOpen())
46
+ if (!getOpen() || !acceptsClick(e))
47
47
  return;
48
48
  if (isInsideInspectorUi(e)) {
49
49
  // The selector guards the inspected application only. Clicks on the
@@ -61,13 +61,10 @@ export function installElementSelector(inspectorHost) {
61
61
  blockApplicationClick(e);
62
62
  return;
63
63
  }
64
- if (isApplicationActivationClick(e))
65
- return;
66
64
  // The inspector is an editing surface while open. Capture every ordinary
67
65
  // application click so buttons, links, and untracked controls cannot run
68
66
  // alongside selection. Shift-click toggles the primary target in the
69
- // ordered group; Command/Ctrl-click still selects the deepest tracked
70
- // element, and Command/Ctrl+Shift-click remains the activation escape hatch.
67
+ // ordered group; Command/Ctrl-click selects the deepest tracked element.
71
68
  const sel = resolveSelectionFromEvent(e, inspectorHost);
72
69
  blockApplicationClick(e);
73
70
  if (sel) {
@@ -89,12 +86,26 @@ export function installElementSelector(inspectorHost) {
89
86
  clickCount: e.detail,
90
87
  }));
91
88
  }
89
+ function onApplicationGesture(e) {
90
+ if (!getOpen() || !acceptsClick(e) || isInlineEditorTarget(e.target))
91
+ return;
92
+ if (e.target instanceof Element
93
+ && (e.target === inspectorHost || inspectorHost.contains(e.target)))
94
+ return;
95
+ blockApplicationGesture(e);
96
+ }
92
97
  document.addEventListener("mousedown", onMouseDown, true);
93
98
  document.addEventListener("dblclick", onDoubleClick, true);
94
99
  document.addEventListener("click", onClick, true);
100
+ for (const type of APPLICATION_GESTURE_EVENTS) {
101
+ document.addEventListener(type, onApplicationGesture, true);
102
+ }
95
103
  return () => {
96
104
  document.removeEventListener("mousedown", onMouseDown, true);
97
105
  document.removeEventListener("dblclick", onDoubleClick, true);
98
106
  document.removeEventListener("click", onClick, true);
107
+ for (const type of APPLICATION_GESTURE_EVENTS) {
108
+ document.removeEventListener(type, onApplicationGesture, true);
109
+ }
99
110
  };
100
111
  }
@@ -1,8 +1,10 @@
1
+ import { DESIGN_SELECT_CURSOR, INTERACTION_CURSOR_PROPERTY } from "../ui/customCursors.js";
1
2
  const INTERACTION_STYLE_ID = "nudge-ui-interaction-styles";
2
3
  const interactionStyleDocuments = new Set();
3
4
  const INTERACTION_CSS = `
5
+ html, body,
4
6
  [data-cid], [data-cid] * {
5
- cursor: default !important;
7
+ cursor: var(${INTERACTION_CURSOR_PROPERTY}, ${DESIGN_SELECT_CURSOR}) !important;
6
8
  -webkit-user-select: none !important;
7
9
  user-select: none !important;
8
10
  }
@@ -16,7 +16,7 @@ export interface SpacingGuideData {
16
16
  guide: Rect;
17
17
  affectedGuides: Rect[];
18
18
  affectedAreas: Rect[];
19
- /** A 24px-thick pointer target centred on the visible, up-to-40px guide handle. */
19
+ /** A 16px-thick pointer target centred on the visible, up-to-40px guide handle. */
20
20
  hit: Rect;
21
21
  }
22
22
  export interface SpacingAffordance extends SpacingGuideData {
@@ -30,16 +30,28 @@ export interface SpacingDescriptor {
30
30
  export declare const SPACING_GUIDE_HANDLE_LENGTH = 40;
31
31
  /** Finds the spacing target under a document-local pointer location. */
32
32
  export declare function getSpacingAffordanceAtPoint(doc: Document, x: number, y: number): SpacingAffordance | null;
33
+ /** Finds the spacing target whose visible padding or gap area contains the
34
+ * pointer, even when the pointer is outside the drag handle. Hover previews use
35
+ * this; drags and the resize cursor still require the handle hit from
36
+ * getSpacingAffordanceAtPoint. */
37
+ export declare function getSpacingHoverAtPoint(doc: Document, x: number, y: number): SpacingAffordance | null;
33
38
  /** Re-resolves a renderer-reported spacing descriptor in its owner document. */
34
39
  export declare function getSpacingAffordanceForDescriptor(element: HTMLElement, descriptor: SpacingDescriptor): SpacingAffordance | null;
35
- /** Calculates the pixel value represented by a direct-manipulation drag. */
40
+ /**
41
+ * Calculates a direct-manipulation value, optionally stepping changes by 8px.
42
+ * While Shift is held the value snaps to a step anchor: the first displacement
43
+ * picks the nearest multiple of 8 from the authored value in the drag
44
+ * direction (ties resolve upward), and further movement adds whole 8px steps
45
+ * from that anchor, so the result is always a multiple of 8 once the drag
46
+ * moves. At the exact start point the authored value is preserved.
47
+ */
36
48
  export declare function spacingValueForDrag(affordance: Pick<SpacingAffordance, "dragAxis" | "direction" | "value">, start: {
37
49
  x: number;
38
50
  y: number;
39
51
  }, point: {
40
52
  x: number;
41
53
  y: number;
42
- }): number;
54
+ }, shiftKey?: boolean): number;
43
55
  export declare function spacingValueCss(value: number): string;
44
56
  /** Serializes the stable part of an affordance for renderer-to-controller messages. */
45
57
  export declare function toSpacingDescriptor(affordance: SpacingAffordance): SpacingDescriptor;
@@ -1,6 +1,7 @@
1
1
  import { getElementComputedStyle } from "../runtime/domRealm.js";
2
- const SPACING_DRAG_TARGET_SIZE = 24;
2
+ const SPACING_DRAG_TARGET_SIZE = 16;
3
3
  export const SPACING_GUIDE_HANDLE_LENGTH = 40;
4
+ const SPACING_SHIFT_STEP = 8;
4
5
  const EPSILON = 0.01;
5
6
  function rightOf(rect) {
6
7
  return Number.isFinite(rect.right) ? rect.right : rect.left + rect.width;
@@ -87,10 +88,10 @@ const PADDING_CONFIG = {
87
88
  bottom: { axis: "horizontal", dragAxis: "y", direction: 1 },
88
89
  left: { axis: "vertical", dragAxis: "x", direction: 1 },
89
90
  };
90
- function paddingAffordanceForSide(element, side, allowZero, model = boxModel(element)) {
91
+ function paddingAffordanceForSide(element, side, model = boxModel(element)) {
91
92
  const { inner, content, padding } = model;
92
93
  const value = padding[side];
93
- if (!allowZero && value <= EPSILON)
94
+ if (value <= EPSILON)
94
95
  return null;
95
96
  const config = PADDING_CONFIG[side];
96
97
  const width = Math.max(0, inner.right - inner.left);
@@ -138,13 +139,13 @@ function paddingAffordanceForSide(element, side, allowZero, model = boxModel(ele
138
139
  element,
139
140
  };
140
141
  }
141
- function paddingAffordanceAtPoint(element, x, y, allowZero) {
142
+ function paddingAffordanceAtPoint(element, x, y) {
142
143
  const model = boxModel(element);
143
144
  if (!containsPoint(model.outer, x, y))
144
145
  return null;
145
146
  const sides = ["top", "right", "bottom", "left"];
146
147
  for (const side of sides) {
147
- const affordance = paddingAffordanceForSide(element, side, allowZero, model);
148
+ const affordance = paddingAffordanceForSide(element, side, model);
148
149
  if (affordance && containsRectPoint(affordance.hit, x, y))
149
150
  return affordance;
150
151
  }
@@ -262,6 +263,52 @@ function gapDragHit(segment) {
262
263
  const orientation = segment.axis === "horizontal" ? "vertical" : "horizontal";
263
264
  return guideHit(gapGuide(segment), orientation);
264
265
  }
266
+ /** Matches the padding bar whose visible area contains the pointer, whether or
267
+ * not the point is inside the drag handle. Returns the first side by the same
268
+ * priority order as the drag affordances so both paths agree on overlaps. */
269
+ function paddingAffordanceInAreaAtPoint(element, x, y) {
270
+ const model = boxModel(element);
271
+ if (!containsPoint(model.outer, x, y))
272
+ return null;
273
+ const sides = ["top", "right", "bottom", "left"];
274
+ for (const side of sides) {
275
+ const affordance = paddingAffordanceForSide(element, side, model);
276
+ if (affordance
277
+ && affordance.affectedAreas.some((area) => containsRectPoint(area, x, y))) {
278
+ return affordance;
279
+ }
280
+ }
281
+ return null;
282
+ }
283
+ /** Matches a layout gap whose visible area contains the pointer, whether or not
284
+ * the point is inside the drag handle. Shares segment priority and geometry
285
+ * with gapAffordanceAtPoint so hover and drag agree on crossed gap properties. */
286
+ function gapAffordanceInAreaAtPoint(element, x, y) {
287
+ const segments = gapSegments(element);
288
+ if (segments.length === 0)
289
+ return null;
290
+ const candidate = segments.find((segment) => containsRectPoint(gapArea(segment), x, y));
291
+ if (!candidate)
292
+ return null;
293
+ const matchingSegments = segments.filter((segment) => segment.property === candidate.property);
294
+ const first = matchingSegments[0];
295
+ const guide = gapGuide(first);
296
+ return {
297
+ kind: "gap",
298
+ property: first.property,
299
+ side: null,
300
+ axis: first.axis,
301
+ dragAxis: first.axis === "horizontal" ? "x" : "y",
302
+ value: gapValue(getElementComputedStyle(element), first.property),
303
+ cursor: first.axis === "horizontal" ? "ew-resize" : "ns-resize",
304
+ guide,
305
+ affectedGuides: matchingSegments.map(gapGuide),
306
+ affectedAreas: matchingSegments.map(gapArea),
307
+ hit: gapDragHit(first),
308
+ direction: 1,
309
+ element,
310
+ };
311
+ }
265
312
  function gapValue(style, property) {
266
313
  const direct = style.getPropertyValue(property)
267
314
  || (property === "row-gap" ? style.rowGap : style.columnGap);
@@ -301,7 +348,7 @@ function trackedElementsAtPoint(doc, x, y) {
301
348
  export function getSpacingAffordanceAtPoint(doc, x, y) {
302
349
  const candidates = trackedElementsAtPoint(doc, x, y);
303
350
  for (const element of candidates) {
304
- const padding = paddingAffordanceAtPoint(element, x, y, false);
351
+ const padding = paddingAffordanceAtPoint(element, x, y);
305
352
  if (padding)
306
353
  return padding;
307
354
  }
@@ -310,13 +357,24 @@ export function getSpacingAffordanceAtPoint(doc, x, y) {
310
357
  if (gap)
311
358
  return gap;
312
359
  }
313
- // A zero-sized padding region still needs a small draggable edge so users
314
- // can establish padding without first typing a value in the inspector.
360
+ return null;
361
+ }
362
+ /** Finds the spacing target whose visible padding or gap area contains the
363
+ * pointer, even when the pointer is outside the drag handle. Hover previews use
364
+ * this; drags and the resize cursor still require the handle hit from
365
+ * getSpacingAffordanceAtPoint. */
366
+ export function getSpacingHoverAtPoint(doc, x, y) {
367
+ const candidates = trackedElementsAtPoint(doc, x, y);
315
368
  for (const element of candidates) {
316
- const padding = paddingAffordanceAtPoint(element, x, y, true);
369
+ const padding = paddingAffordanceInAreaAtPoint(element, x, y);
317
370
  if (padding)
318
371
  return padding;
319
372
  }
373
+ for (const element of candidates) {
374
+ const gap = gapAffordanceInAreaAtPoint(element, x, y);
375
+ if (gap)
376
+ return gap;
377
+ }
320
378
  return null;
321
379
  }
322
380
  /** Re-resolves a renderer-reported spacing descriptor in its owner document. */
@@ -325,7 +383,7 @@ export function getSpacingAffordanceForDescriptor(element, descriptor) {
325
383
  const side = descriptor.side;
326
384
  if (!side || descriptor.property !== `padding-${side}`)
327
385
  return null;
328
- return paddingAffordanceForSide(element, side, true);
386
+ return paddingAffordanceForSide(element, side);
329
387
  }
330
388
  if (descriptor.property !== "row-gap" && descriptor.property !== "column-gap")
331
389
  return null;
@@ -335,10 +393,27 @@ export function getSpacingAffordanceForDescriptor(element, descriptor) {
335
393
  const guide = gapGuide(segment);
336
394
  return gapAffordanceAtPoint(element, guide.left + guide.width / 2, guide.top + guide.height / 2, descriptor.property);
337
395
  }
338
- /** Calculates the pixel value represented by a direct-manipulation drag. */
339
- export function spacingValueForDrag(affordance, start, point) {
396
+ /**
397
+ * Calculates a direct-manipulation value, optionally stepping changes by 8px.
398
+ * While Shift is held the value snaps to a step anchor: the first displacement
399
+ * picks the nearest multiple of 8 from the authored value in the drag
400
+ * direction (ties resolve upward), and further movement adds whole 8px steps
401
+ * from that anchor, so the result is always a multiple of 8 once the drag
402
+ * moves. At the exact start point the authored value is preserved.
403
+ */
404
+ export function spacingValueForDrag(affordance, start, point, shiftKey = false) {
340
405
  const delta = affordance.dragAxis === "x" ? point.x - start.x : point.y - start.y;
341
- return Math.max(0, Math.round(affordance.value + delta * affordance.direction));
406
+ const signedDelta = delta * affordance.direction;
407
+ if (shiftKey) {
408
+ const step = SPACING_SHIFT_STEP;
409
+ if (signedDelta !== 0) {
410
+ const anchor = signedDelta > 0
411
+ ? Math.ceil(affordance.value / step) * step
412
+ : Math.floor(affordance.value / step) * step;
413
+ return Math.max(0, anchor + Math.trunc(signedDelta / step) * step);
414
+ }
415
+ }
416
+ return Math.max(0, Math.round(affordance.value + signedDelta));
342
417
  }
343
418
  export function spacingValueCss(value) {
344
419
  return `${Math.max(0, Math.round(value))}px`;
@@ -3,8 +3,8 @@ import type { RenderedInstanceOverride } from "../changes/editModel.js";
3
3
  import { type StructuralChange } from "./structuralProjection.js";
4
4
  import type { ComponentOverride } from "../componentSemantics/types.js";
5
5
  import { type TextContentChangeRecord } from "../changes/types.js";
6
- import type { WorkspaceContents } from "../changes/workspaceChanges.js";
7
- export interface WorkspaceProjectionSource extends WorkspaceContents {
6
+ import type { DraftContents } from "../changes/draftChanges.js";
7
+ export interface DraftProjectionSource extends DraftContents {
8
8
  readonly revision: number;
9
9
  }
10
10
  export interface CompiledManagedStyles {
@@ -15,7 +15,7 @@ export interface SerializedManagedStyles {
15
15
  readonly css: string;
16
16
  }
17
17
  /** A complete, read-only projection for one document-local runtime. */
18
- export interface WorkspaceProjectionPlan<ManagedStyles> {
18
+ export interface DraftProjectionPlan<ManagedStyles> {
19
19
  readonly sourceRevision: number;
20
20
  readonly managedStyles: ManagedStyles;
21
21
  readonly instanceOverrides: readonly RenderedInstanceOverride[];
@@ -31,7 +31,7 @@ export interface DocumentProjectionAdapter<ManagedStyles> {
31
31
  applyComponents(overrides: readonly ComponentOverride[]): void;
32
32
  applyManagedStyles(styles: ManagedStyles): void;
33
33
  }
34
- export declare function compileWorkspaceProjection(snapshot: WorkspaceProjectionSource): WorkspaceProjectionPlan<CompiledManagedStyles>;
34
+ export declare function compileDraftProjection(snapshot: DraftProjectionSource): DraftProjectionPlan<CompiledManagedStyles>;
35
35
  /**
36
36
  * Replaces one document projection in the required order.
37
37
  *
@@ -39,5 +39,5 @@ export declare function compileWorkspaceProjection(snapshot: WorkspaceProjection
39
39
  * can depend on the restored element order. Managed CSS is applied last so
40
40
  * selectors can use the document-local instance markers installed above.
41
41
  */
42
- export declare function applyWorkspaceProjection<ManagedStyles>(adapter: DocumentProjectionAdapter<ManagedStyles>, plan: WorkspaceProjectionPlan<ManagedStyles>): void;
43
- export declare function applyHostWorkspaceProjection(plan: WorkspaceProjectionPlan<CompiledManagedStyles>): void;
42
+ export declare function applyDraftProjection<ManagedStyles>(adapter: DocumentProjectionAdapter<ManagedStyles>, plan: DraftProjectionPlan<ManagedStyles>): void;
43
+ export declare function applyHostDraftProjection(plan: DraftProjectionPlan<CompiledManagedStyles>): void;
@@ -6,7 +6,7 @@ import { replaceComponentOverrideProjection } from "../componentSemantics/index.
6
6
  import { componentChangeToOverride } from "../componentSemantics/changeModel.js";
7
7
  import { isComponentChange } from "../changes/types.js";
8
8
  import { buildManagedStyleRules } from "../changes/managedStyleProjection.js";
9
- export function compileWorkspaceProjection(snapshot) {
9
+ export function compileDraftProjection(snapshot) {
10
10
  const changes = [...snapshot.changes];
11
11
  const rules = buildManagedStyleRules(changes);
12
12
  return {
@@ -31,7 +31,7 @@ export function compileWorkspaceProjection(snapshot) {
31
31
  * can depend on the restored element order. Managed CSS is applied last so
32
32
  * selectors can use the document-local instance markers installed above.
33
33
  */
34
- export function applyWorkspaceProjection(adapter, plan) {
34
+ export function applyDraftProjection(adapter, plan) {
35
35
  adapter.applyStructural(plan.structuralChanges);
36
36
  adapter.applyRenderedInstances(plan.instanceOverrides);
37
37
  adapter.applyText(plan.textContentChanges);
@@ -53,6 +53,6 @@ const hostDocumentProjectionAdapter = {
53
53
  applyRules([...styles.rules]);
54
54
  },
55
55
  };
56
- export function applyHostWorkspaceProjection(plan) {
57
- applyWorkspaceProjection(hostDocumentProjectionAdapter, plan);
56
+ export function applyHostDraftProjection(plan) {
57
+ applyDraftProjection(hostDocumentProjectionAdapter, plan);
58
58
  }
@@ -1,3 +1,4 @@
1
+ import type { FrameProjection } from "../canvas/projection.js";
1
2
  import type { RenderedInstanceOverride, RenderedInstanceRef } from "../changes/editModel.js";
2
3
  export { isRenderedInstanceOverride, isRenderedInstanceRef } from "../changes/editModel.js";
3
4
  export type { RenderedInstanceOverride, RenderedInstanceRef, SourceSiteRef } from "../changes/editModel.js";
@@ -50,7 +51,7 @@ export declare function getRenderedInstanceProjectionReports(doc: Document): rea
50
51
  /** Diagnostics arrive independently when a renderer reports or React reconciles. */
51
52
  export declare function subscribeRenderedInstanceDiagnostics(listener: () => void): () => void;
52
53
  export declare function getRenderedInstanceDiagnosticRevision(): number;
53
- export declare function recordCanvasRenderedInstanceProjectionReports(cardId: string, revision: number, reports: readonly DocumentProjectionReport[]): void;
54
+ export declare function recordCanvasRenderedInstanceProjectionReports(cardId: string, revision: number, reports: readonly DocumentProjectionReport[], projection?: FrameProjection): void;
54
55
  export declare function clearCanvasRenderedInstanceProjectionReports(cardId: string): void;
55
56
  export declare function getRenderedInstanceChangeDiagnostics(overrideId: string): RenderedInstanceChangeDiagnostic[];
56
57
  export declare function isDocumentProjectionReport(value: unknown): value is DocumentProjectionReport;
@@ -1,3 +1,4 @@
1
+ import { getActiveDraftChanges, getDraftChanges } from "../changes/draftChanges.js";
1
2
  import { escapeAttrValue } from "./cssEscapes.js";
2
3
  import { isNudgeUiDev } from "../runtime/devFlag.js";
3
4
  import { sourceSiteSelector } from "../selection/sourceSite.js";
@@ -74,8 +75,8 @@ export function resolveRenderedInstance(doc, ref) {
74
75
  /** Checks stable source/evidence fields without treating a post-move ordinal as identity. */
75
76
  export function matchesRenderedInstanceEvidence(el, ref) {
76
77
  const { props, text, ariaLabel = null } = ref.locator;
77
- return el.getAttribute("data-cid") === ref.sourceSite.cid
78
- && el.getAttribute("data-src") === ref.sourceSite.src
78
+ return (el.getAttribute("data-cid") ?? "") === ref.sourceSite.cid
79
+ && (el.getAttribute("data-src") ?? "") === ref.sourceSite.src
79
80
  && el.getAttribute("data-cprops") === props
80
81
  && normalizedText(el) === text
81
82
  && el.getAttribute("aria-label") === ariaLabel;
@@ -254,10 +255,10 @@ export function subscribeRenderedInstanceDiagnostics(listener) {
254
255
  export function getRenderedInstanceDiagnosticRevision() {
255
256
  return diagnosticRevision;
256
257
  }
257
- export function recordCanvasRenderedInstanceProjectionReports(cardId, revision, reports) {
258
+ export function recordCanvasRenderedInstanceProjectionReports(cardId, revision, reports, projection) {
258
259
  if (!Number.isSafeInteger(revision) || revision < 0 || !reports.every(isDocumentProjectionReport))
259
260
  return;
260
- const expected = new Set(canonicalOverrides.keys());
261
+ const expected = projection ? new Set(projection.instanceOverrides.map((record) => record.id)) : new Set(canonicalOverrides.keys());
261
262
  if (reports.length !== expected.size || new Set(reports.map((report) => report.overrideId)).size !== reports.length
262
263
  || reports.some((report) => !expected.has(report.overrideId)))
263
264
  return;
@@ -267,7 +268,8 @@ export function recordCanvasRenderedInstanceProjectionReports(cardId, revision,
267
268
  const next = reports.map((report) => ({ ...report }));
268
269
  if (existing && existing.revision === revision && sameReports(existing.reports, next))
269
270
  return;
270
- reportsByCanvasCard.set(cardId, { revision, reports: next });
271
+ const current = getActiveDraftChanges();
272
+ reportsByCanvasCard.set(cardId, { revision, reports: next, draftId: projection?.draftId ?? current.draftId, draftRevision: projection?.draftRevision ?? current.revision });
271
273
  notifyDiagnostics();
272
274
  }
273
275
  export function clearCanvasRenderedInstanceProjectionReports(cardId) {
@@ -281,6 +283,8 @@ export function getRenderedInstanceChangeDiagnostics(overrideId) {
281
283
  if (host)
282
284
  diagnostics.push({ ...host, document: "Inspect" });
283
285
  for (const [cardId, entry] of reportsByCanvasCard) {
286
+ if (entry.draftId !== getActiveDraftChanges().draftId || entry.draftRevision !== getDraftChanges(entry.draftId).revision)
287
+ continue;
284
288
  const report = entry.reports.find((candidate) => candidate.overrideId === overrideId);
285
289
  if (report)
286
290
  diagnostics.push({ ...report, document: `Canvas ${cardId}` });
@@ -1,3 +1,4 @@
1
+ import type { FrameProjection } from "../canvas/projection.js";
1
2
  import type { StructuralChange, StructuralDelete, StructuralMove, StructuralProjectionReason, StructuralProjectionReport } from "../changes/structuralTypes.js";
2
3
  export { isStructuralChange, isStructuralDelete, isStructuralMove, isStructuralProjectionReport, } from "./structuralProjectionBoundary.js";
3
4
  /**
@@ -76,7 +77,7 @@ export declare function getStructuralProjectionReports(doc: Document): readonly
76
77
  * Frames may report only their document-local outcome. The controller owns
77
78
  * these reports and filters them against its current canonical change set.
78
79
  */
79
- export declare function recordCanvasStructuralProjectionReports(cardId: string, revision: number, reports: readonly StructuralProjectionReport[]): void;
80
+ export declare function recordCanvasStructuralProjectionReports(cardId: string, revision: number, reports: readonly StructuralProjectionReport[], projection?: FrameProjection): void;
80
81
  export declare function clearCanvasStructuralProjectionReports(cardId: string): void;
81
82
  /** Removes document-local reports for canonical intents that no longer exist. */
82
83
  export declare function pruneStructuralProjectionReports(changeIds: ReadonlySet<string>): void;
@@ -1,6 +1,7 @@
1
+ import { getActiveDraftChanges, getDraftChanges } from "../changes/draftChanges.js";
1
2
  import { captureRenderedInstance, matchesRenderedInstanceEvidence, resolveRenderedInstance, } from "./renderedInstance.js";
2
3
  import { isStructuralProjectionReport } from "./structuralProjectionBoundary.js";
3
- import { resetWorkspaceChanges, workspaceChangeStore, } from "../changes/workspaceChanges.js";
4
+ import { resetDraftChanges, draftChangeStore, } from "../changes/draftChanges.js";
4
5
  export { isStructuralChange, isStructuralDelete, isStructuralMove, isStructuralProjectionReport, } from "./structuralProjectionBoundary.js";
5
6
  const VOID_PARENT_TAGS = new Set([
6
7
  "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr",
@@ -193,9 +194,9 @@ export function createStructuralDelete(element, id = structuralId()) {
193
194
  ...(route ? { route } : {}),
194
195
  ...(state ? { state } : {}),
195
196
  };
196
- if (!workspaceChangeStore.commitStructuralChange(change))
197
+ if (!draftChangeStore.commitStructuralChange(change))
197
198
  return null;
198
- projectStructuralChanges(workspaceChangeStore.getSnapshot());
199
+ projectStructuralChanges(draftChangeStore.getSnapshot());
199
200
  return change;
200
201
  }
201
202
  /**
@@ -236,22 +237,22 @@ export function createStructuralMove(element, destination, id = structuralId())
236
237
  : destinationChildren.length - (sameParent ? 1 : 0),
237
238
  },
238
239
  };
239
- if (!workspaceChangeStore.commitStructuralChange(change))
240
+ if (!draftChangeStore.commitStructuralChange(change))
240
241
  return null;
241
- projectStructuralChanges(workspaceChangeStore.getSnapshot());
242
+ projectStructuralChanges(draftChangeStore.getSnapshot());
242
243
  return change;
243
244
  }
244
245
  export function getStructuralChanges() {
245
- return workspaceChangeStore.getSnapshot().structuralChanges;
246
+ return draftChangeStore.getSnapshot().structuralChanges;
246
247
  }
247
248
  export function getStructuralDeletes() {
248
249
  return getStructuralChanges().filter((change) => change.kind === "delete");
249
250
  }
250
251
  /** Revert removes one canonical intent and leaves every other intent intact. */
251
252
  export function revertStructuralChange(changeId) {
252
- const changed = workspaceChangeStore.revertStructuralChangeRecord(changeId);
253
+ const changed = draftChangeStore.revertStructuralChangeRecord(changeId);
253
254
  if (changed)
254
- projectStructuralChanges(workspaceChangeStore.getSnapshot());
255
+ projectStructuralChanges(draftChangeStore.getSnapshot());
255
256
  return changed;
256
257
  }
257
258
  /**
@@ -265,10 +266,10 @@ export function revertStructuralChange(changeId) {
265
266
  export function reconcileVerifiedStructuralChanges(verifiedIds) {
266
267
  if (verifiedIds.size === 0)
267
268
  return 0;
268
- const removed = workspaceChangeStore.reconcileWorkspaceChanges(new Set(), verifiedIds);
269
+ const removed = draftChangeStore.reconcileActiveDraftChanges(new Set(), verifiedIds);
269
270
  if (removed === 0)
270
271
  return 0;
271
- projectStructuralChanges(workspaceChangeStore.getSnapshot());
272
+ projectStructuralChanges(draftChangeStore.getSnapshot());
272
273
  for (const [cardId, canvasReports] of reportsByCanvasCard) {
273
274
  reportsByCanvasCard.set(cardId, {
274
275
  ...canvasReports,
@@ -280,7 +281,7 @@ export function reconcileVerifiedStructuralChanges(verifiedIds) {
280
281
  }
281
282
  /** State changes drive controller-to-renderer projection. Diagnostics do not. */
282
283
  export function subscribeStructuralChanges(listener) {
283
- return workspaceChangeStore.subscribe(listener);
284
+ return draftChangeStore.subscribe(listener);
284
285
  }
285
286
  /** Compatibility name retained while the controller moved to a full union. */
286
287
  export const subscribeStructuralDeletes = subscribeStructuralChanges;
@@ -549,10 +550,10 @@ export function getStructuralProjectionReports(doc) {
549
550
  * Frames may report only their document-local outcome. The controller owns
550
551
  * these reports and filters them against its current canonical change set.
551
552
  */
552
- export function recordCanvasStructuralProjectionReports(cardId, revision, reports) {
553
+ export function recordCanvasStructuralProjectionReports(cardId, revision, reports, projection) {
553
554
  if (!Number.isSafeInteger(revision) || revision < 0 || !reports.every(isStructuralProjectionReport))
554
555
  return;
555
- const expected = new Set(getStructuralChanges().map((change) => change.id));
556
+ const expected = projection ? new Set(projection.structuralChanges.map((record) => record.id)) : new Set(getStructuralChanges().map((change) => change.id));
556
557
  if (reports.length !== expected.size || new Set(reports.map((report) => report.changeId)).size !== reports.length
557
558
  || reports.some((report) => !expected.has(report.changeId)))
558
559
  return;
@@ -562,7 +563,8 @@ export function recordCanvasStructuralProjectionReports(cardId, revision, report
562
563
  const next = reports.map((report) => ({ ...report }));
563
564
  if (existing && existing.revision === revision && sameReports(existing.reports, next))
564
565
  return;
565
- reportsByCanvasCard.set(cardId, { revision, reports: next });
566
+ const current = getActiveDraftChanges();
567
+ reportsByCanvasCard.set(cardId, { revision, reports: next, draftId: projection?.draftId ?? current.draftId, draftRevision: projection?.draftRevision ?? current.revision });
566
568
  notifyDiagnostics();
567
569
  }
568
570
  export function clearCanvasStructuralProjectionReports(cardId) {
@@ -594,6 +596,8 @@ export function getStructuralChangeDiagnostics(changeId) {
594
596
  if (host)
595
597
  diagnostics.push({ ...host, document: "Inspect" });
596
598
  for (const [cardId, entry] of reportsByCanvasCard) {
599
+ if (entry.draftId !== getActiveDraftChanges().draftId || entry.draftRevision !== getDraftChanges(entry.draftId).revision)
600
+ continue;
597
601
  const report = entry.reports.find((candidate) => candidate.changeId === changeId);
598
602
  if (report)
599
603
  diagnostics.push({ ...report, document: `Canvas ${cardId}` });
@@ -615,7 +619,7 @@ export function resetStructuralDeleteProjection() {
615
619
  reportsByCanvasCard.clear();
616
620
  nextStructuralId = 1;
617
621
  diagnosticRevision = 0;
618
- resetWorkspaceChanges();
622
+ resetDraftChanges();
619
623
  notifyDiagnostics();
620
624
  }
621
625
  /**
@@ -1,3 +1,4 @@
1
+ import type { FrameProjection } from "../canvas/projection.js";
1
2
  import { isTextProjectionTargetValue, type TextContentChangeRecord, type TextProjectionTarget, type TextProjectionScope, type TextBindingEvidence } from "../inline-text/textChangeBoundary.js";
2
3
  /** Strict JSON boundary guard for a text projection target. */
3
4
  export declare const isTextProjectionTarget: typeof isTextProjectionTargetValue;
@@ -48,7 +49,7 @@ export declare function setCanonicalTextContentChanges(changes: ReadonlyArray<Te
48
49
  export declare function getTextProjectionReports(doc: Document): readonly TextProjectionReport[];
49
50
  export declare function subscribeTextProjectionDiagnostics(listener: () => void): () => void;
50
51
  export declare function getTextProjectionDiagnosticRevision(): number;
51
- export declare function recordCanvasTextProjectionReports(cardId: string, revision: number, reports: readonly TextProjectionReport[]): void;
52
+ export declare function recordCanvasTextProjectionReports(cardId: string, revision: number, reports: readonly TextProjectionReport[], projection?: FrameProjection): void;
52
53
  export declare function clearCanvasTextProjectionReports(cardId: string): void;
53
54
  export declare function getTextContentChangeDiagnostics(changeId: string): TextContentProjectionDiagnostic[];
54
55
  export declare function isTextProjectionReport(value: unknown): value is TextProjectionReport;
@@ -1,3 +1,4 @@
1
+ import { getActiveDraftChanges, getDraftChanges } from "../changes/draftChanges.js";
1
2
  import { sourceSiteSelector } from "../selection/sourceSite.js";
2
3
  import { isNudgeUiDev } from "../runtime/devFlag.js";
3
4
  import { isTextContentChangeValue, isTextProjectionTargetValue, } from "../inline-text/textChangeBoundary.js";
@@ -640,10 +641,10 @@ export function subscribeTextProjectionDiagnostics(listener) {
640
641
  export function getTextProjectionDiagnosticRevision() {
641
642
  return diagnosticRevision;
642
643
  }
643
- export function recordCanvasTextProjectionReports(cardId, revision, reports) {
644
+ export function recordCanvasTextProjectionReports(cardId, revision, reports, projection) {
644
645
  if (!Number.isSafeInteger(revision) || revision < 0 || !reports.every(isTextProjectionReport))
645
646
  return;
646
- const expected = new Set(canonicalChanges.keys());
647
+ const expected = projection ? new Set(projection.textContentChanges.map((record) => record.id)) : new Set(canonicalChanges.keys());
647
648
  if (reports.length !== expected.size
648
649
  || new Set(reports.map((report) => report.changeId)).size !== reports.length
649
650
  || reports.some((report) => !expected.has(report.changeId)))
@@ -654,7 +655,8 @@ export function recordCanvasTextProjectionReports(cardId, revision, reports) {
654
655
  const next = reports.map((report) => ({ ...report }));
655
656
  if (existing && existing.revision === revision && sameReports(existing.reports, next))
656
657
  return;
657
- reportsByCanvasCard.set(cardId, { revision, reports: next });
658
+ const current = getActiveDraftChanges();
659
+ reportsByCanvasCard.set(cardId, { revision, reports: next, draftId: projection?.draftId ?? current.draftId, draftRevision: projection?.draftRevision ?? current.revision });
658
660
  notifyDiagnostics();
659
661
  }
660
662
  export function clearCanvasTextProjectionReports(cardId) {
@@ -664,7 +666,7 @@ export function clearCanvasTextProjectionReports(cardId) {
664
666
  }
665
667
  export function getTextContentChangeDiagnostics(changeId) {
666
668
  const diagnostics = [];
667
- const change = canonicalChanges.get(changeId);
669
+ const change = getActiveDraftChanges().changes.find((change) => change.kind === "text-content" && change.id === changeId) ?? canonicalChanges.get(changeId);
668
670
  const host = reportsByDocument.get(document)?.find((report) => report.changeId === changeId);
669
671
  if (host)
670
672
  diagnostics.push({
@@ -674,6 +676,8 @@ export function getTextContentChangeDiagnostics(changeId) {
674
676
  evidence: change?.evidence,
675
677
  });
676
678
  for (const [cardId, entry] of reportsByCanvasCard) {
679
+ if (entry.draftId !== getActiveDraftChanges().draftId || entry.draftRevision !== getDraftChanges(entry.draftId).revision)
680
+ continue;
677
681
  const report = entry.reports.find((candidate) => candidate.changeId === changeId);
678
682
  if (report)
679
683
  diagnostics.push({
@@ -2,11 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { useRef } from "react";
3
3
  import { Dialog } from "@base-ui/react/dialog";
4
4
  import { IconX } from "@tabler/icons-react";
5
- function portalContainer() {
6
- return typeof document !== "undefined"
7
- ? document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body
8
- : null;
9
- }
5
+ import { portalContainer } from "../ui/portalContainer.js";
10
6
  /** Edits the instructions appended to every generated prompt. */
11
7
  export function PromptSettingsFields({ value, onChange, instructionsRef, }) {
12
8
  return (_jsxs(_Fragment, { children: [_jsx("div", { className: "prompt-settings__field", children: _jsx("textarea", { ref: instructionsRef, id: "nudge-ui-custom-instructions", className: "prompt-settings__textarea", "data-test": "prompt-custom-instructions", "aria-label": "Custom instructions", rows: 6, value: value, onChange: (event) => onChange(event.currentTarget.value) }) }), _jsx("div", { className: "prompt-settings__actions", children: _jsx(Dialog.Close, { className: "button button--primary", "data-test": "prompt-settings-done", type: "button", children: "Done" }) })] }));