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
@@ -1,18 +1,21 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
3
3
  import { PROTOCOL_VERSION, isElementClickMessage, isInlineTextIntentMessage, } from "./frameProtocol.js";
4
- import { useBoardCamera, useCanvasCards, useCanvasPresentation, useCanvasPresentationTransitioning } from "./canvasStore.js";
4
+ import { useCanvasCards } from "./canvasStore.js";
5
+ import { useBoardCamera, useCanvasPresentation, useCanvasPresentationTransitioning, useCanvasLayoutTransitioning, getCanvasLayoutTransitioning, useTemporaryAppInteraction, } from "./viewStore.js";
5
6
  import { handleElementClick } from "./rendererSelectionProxy.js";
6
- import { getSelectedElements, useSelectedElement, useSelectedElements } from "../selection/selectionStore.js";
7
+ import { getSelectedElements, useHierarchy, useSelectedElement, useSelectedElements } from "../selection/selectionStore.js";
7
8
  import { readBorderWidths, toRect, } from "../overlay/overlayGeometry.js";
8
- const overlayStyles = ".canvas-element-overlay {\n position: fixed;\n pointer-events: none;\n z-index: 1;\n background: transparent;\n outline: 1px solid var(--accent);\n outline-offset: -1px;\n}\n\n.canvas-spacing-guide {\n position: fixed;\n z-index: 1;\n border-radius: 999px;\n background: var(--accent);\n outline: none;\n box-shadow: none;\n pointer-events: none;\n}\n\n.canvas-spacing-fill {\n position: fixed;\n z-index: 1;\n pointer-events: none;\n background: rgb(59 130 246 / 14%);\n}\n\n.canvas-spacing-fill[data-kind=\"gap\"] {\n background: rgb(236 72 153 / 14%);\n}\n\n.canvas-spacing-guide[data-kind=\"gap\"] {\n background: #ec4899;\n}\n\n.canvas-selected-outline {\n position: fixed;\n pointer-events: none;\n z-index: 1;\n outline: 1px solid var(--accent);\n outline-offset: -1px;\n}\n\n.canvas-dom-drop-line {\n z-index: 2147483647;\n border-radius: 999px;\n background: #3b82f6;\n box-shadow: 0 0 0 1px rgb(255 255 255 / 95%), 0 1px 5px rgb(37 99 235 / 72%);\n}\n\n.canvas-dom-drop-line::before,\n.canvas-dom-drop-line::after {\n position: absolute;\n top: 50%;\n width: 8px;\n height: 8px;\n border: 2px solid #ffffff;\n border-radius: 50%;\n background: #2563eb;\n content: \"\";\n transform: translateY(-50%);\n}\n\n.canvas-dom-drop-line::before { left: -3px; }\n.canvas-dom-drop-line::after { right: -3px; }\n\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::before,\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::after {\n left: 50%;\n right: auto;\n transform: translateX(-50%);\n}\n\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::before { top: -3px; }\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::after { top: auto; bottom: -3px; }\n\n.canvas-dom-drop-target {\n z-index: 2147483646;\n box-sizing: border-box;\n border: 1px solid rgb(59 130 246 / 72%);\n border-radius: 4px;\n background: rgb(59 130 246 / 5%);\n}\n";
9
+ const overlayStyles = ".canvas-element-overlay {\n position: fixed;\n pointer-events: none;\n z-index: 1;\n background: transparent;\n outline: 1px solid var(--accent);\n outline-offset: -1px;\n}\n\n.canvas-spacing-guide {\n position: fixed;\n z-index: 1;\n border-radius: 999px;\n background: var(--accent);\n outline: none;\n box-shadow: none;\n pointer-events: none;\n}\n\n.canvas-spacing-fill {\n position: fixed;\n z-index: 1;\n pointer-events: none;\n background: rgb(59 130 246 / 14%);\n}\n\n.canvas-spacing-fill[data-kind=\"gap\"] {\n background: rgb(236 72 153 / 14%);\n}\n\n.canvas-spacing-guide[data-kind=\"gap\"] {\n background: #ec4899;\n}\n\n.canvas-spacing-value-badge {\n position: fixed;\n z-index: 2;\n transform: translate(-50%, calc(-100% - var(--space-8)));\n padding: var(--space-4) var(--space-8);\n border-radius: var(--radius-8);\n background: var(--surface-raised-2x);\n box-shadow: var(--shadow-popup);\n color: var(--text-primary);\n font-family: var(--font-family);\n font-size: var(--font-size-base);\n font-weight: 400;\n line-height: 1.4;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n pointer-events: none;\n}\n\n.canvas-selected-outline {\n position: fixed;\n pointer-events: none;\n z-index: 1;\n outline: 1px solid var(--accent);\n outline-offset: -1px;\n}\n\n.canvas-dom-drop-line {\n z-index: 2147483647;\n border-radius: 999px;\n background: #3b82f6;\n box-shadow: 0 0 0 1px rgb(255 255 255 / 95%), 0 1px 5px rgb(37 99 235 / 72%);\n}\n\n.canvas-dom-drop-line::before,\n.canvas-dom-drop-line::after {\n position: absolute;\n top: 50%;\n width: 8px;\n height: 8px;\n border: 2px solid #ffffff;\n border-radius: 50%;\n background: #2563eb;\n content: \"\";\n transform: translateY(-50%);\n}\n\n.canvas-dom-drop-line::before { left: -3px; }\n.canvas-dom-drop-line::after { right: -3px; }\n\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::before,\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::after {\n left: 50%;\n right: auto;\n transform: translateX(-50%);\n}\n\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::before { top: -3px; }\n.canvas-dom-drop-line[data-orientation=\"vertical\"]::after { top: auto; bottom: -3px; }\n\n.canvas-dom-drop-target {\n z-index: 2147483646;\n box-sizing: border-box;\n border: 1px solid rgb(59 130 246 / 72%);\n border-radius: 4px;\n background: rgb(59 130 246 / 5%);\n}\n";
9
10
  import { deleteElement, getDropLocationAtPoint, moveElement, nudgeElement } from "../overlay/structuralGestures.js";
10
- import { redo, undo } from "../changes/changesLog.js";
11
+ import { changeKey } from "../changes/model.js";
12
+ import { getChanges, redo, subscribeChanges, undo } from "../changes/changesLog.js";
11
13
  import { resolveSelectionFromElement } from "../selection/resolveSelection.js";
12
14
  import { setSelectedElement } from "../selection/selectionStore.js";
13
15
  import { clearDropGuide, showDropGuide, useDropGuide } from "../overlay/dropGuide.js";
14
16
  import { DropGuideOverlay } from "../overlay/DropGuideOverlay.js";
15
17
  import { getMeasurementGeometry } from "../overlay/measurementGeometry.js";
18
+ import { getElementComputedStyle } from "../runtime/domRealm.js";
16
19
  import { MeasurementGuideOverlay } from "../overlay/MeasurementGuideOverlay.js";
17
20
  import { projectMeasurementSegments } from "./measurementProjection.js";
18
21
  import { getRegisteredFrames, PROJECT_ID, WORKSPACE_ID } from "./projection.js";
@@ -23,8 +26,10 @@ import { setInspectorOpen, toggleInspector } from "../shell/openStore.js";
23
26
  import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
24
27
  import { subscribeCanvasRendererMessages } from "./rendererMessageRouter.js";
25
28
  import { setStyles } from "../tokens/editActions.js";
26
- import { getSpacingAffordanceAtPoint, getSpacingAffordanceForDescriptor, SPACING_GUIDE_HANDLE_LENGTH, spacingValueCss, spacingValueForDrag, } from "../overlay/spacingGestures.js";
29
+ import { getSpacingAffordanceAtPoint, getSpacingAffordanceForDescriptor, getSpacingHoverAtPoint, SPACING_GUIDE_HANDLE_LENGTH, spacingValueCss, spacingValueForDrag, } from "../overlay/spacingGestures.js";
27
30
  import { beginLayoutPreview, endLayoutPreview } from "../styleEditors/layoutPreviewState.js";
31
+ import { useNudgeUiRuntimeConfig } from "../runtime/useRuntimeConfig.js";
32
+ import { DomNavigator } from "../overlay/DomNavigator.js";
28
33
  function projectRect(iframe, rect, zoom) {
29
34
  const frameRect = iframe.getBoundingClientRect();
30
35
  return {
@@ -34,6 +39,20 @@ function projectRect(iframe, rect, zoom) {
34
39
  height: rect.height * zoom,
35
40
  };
36
41
  }
42
+ function projectPoint(iframe, x, y, zoom) {
43
+ const frameRect = iframe.getBoundingClientRect();
44
+ return {
45
+ x: frameRect.left + x * zoom,
46
+ y: frameRect.top + y * zoom,
47
+ };
48
+ }
49
+ function spacingBadgeForDrag(drag, point) {
50
+ return {
51
+ iframe: drag.iframe,
52
+ point: { x: point.x, y: point.y },
53
+ value: drag.currentValue,
54
+ };
55
+ }
37
56
  function overlayStyle(rect) {
38
57
  return {
39
58
  position: "fixed",
@@ -104,8 +123,8 @@ function clearSpacingDrag(ref) {
104
123
  if (drag)
105
124
  restoreSpacingPreview(drag);
106
125
  }
107
- function applySpacingPreview(drag, point) {
108
- const value = spacingValueForDrag(drag.affordance, drag.start, point);
126
+ function applySpacingPreview(drag, point, shiftKey = false) {
127
+ const value = spacingValueForDrag(drag.affordance, drag.start, point, shiftKey);
109
128
  drag.currentValue = value;
110
129
  beginLayoutPreview(drag.element, drag.affordance.property);
111
130
  drag.element.style.setProperty(drag.affordance.property, spacingValueCss(value));
@@ -119,19 +138,95 @@ function restoreSpacingPreview(drag) {
119
138
  }
120
139
  endLayoutPreview(drag.element, drag.affordance.property);
121
140
  }
141
+ /**
142
+ * Commits a managed rule for the drag's final value. Returns the created change
143
+ * records (empty for a no-op drag). The preview inline is intentionally left
144
+ * applied at the committed value once a record exists; the caller must register
145
+ * a PendingSpacingCommit and release it after the renderer acknowledges the
146
+ * projected sheet. Restoring the authored declaration first would flash the old
147
+ * value for the postMessage round trip the sheet takes.
148
+ */
122
149
  function commitSpacingDrag(drag) {
123
- // Restore the authored declaration before committing the managed rule. The
124
- // captured start value is the baseline because the pointer remains hovered
125
- // and CSS inspection can still report the transient preview value.
126
- restoreSpacingPreview(drag);
127
- if (drag.currentValue === drag.startValue)
128
- return;
129
- setStyles(drag.element, [{
150
+ if (drag.currentValue === drag.startValue) {
151
+ restoreSpacingPreview(drag);
152
+ return [];
153
+ }
154
+ return setStyles(drag.element, [{
130
155
  property: drag.affordance.property,
131
156
  value: spacingValueCss(drag.currentValue),
132
157
  oldRawValue: spacingValueCss(drag.startValue),
133
158
  }]);
134
159
  }
160
+ /** Removes a deferred preview inline as soon as the projected sheet alone
161
+ * reproduces the committed value; keeps it otherwise and retries on the next
162
+ * projection acknowledgement from that frame. */
163
+ function tryReleasePendingSpacingCommit(commit) {
164
+ const { element, property, committedValue } = commit;
165
+ if (!element.isConnected)
166
+ return true;
167
+ element.style.removeProperty(property);
168
+ const computed = getElementComputedStyle(element).getPropertyValue(property).trim();
169
+ if (computed === committedValue) {
170
+ endLayoutPreview(element, property);
171
+ return true;
172
+ }
173
+ element.style.setProperty(property, committedValue);
174
+ return false;
175
+ }
176
+ function releasePendingSpacingCommits(pending, iframe) {
177
+ if (pending.length === 0)
178
+ return;
179
+ let write = 0;
180
+ for (const commit of pending) {
181
+ if (commit.iframe !== iframe || !tryReleasePendingSpacingCommit(commit)) {
182
+ pending[write] = commit;
183
+ write += 1;
184
+ }
185
+ }
186
+ pending.length = write;
187
+ }
188
+ /** Restores any held preview inline whose committed rule was undone, reverted,
189
+ * or cleared before its sheet landed. Runs synchronously with the workspace
190
+ * change, so the inline never outlives the intent behind it. */
191
+ function reconcilePendingSpacingCommits(pending) {
192
+ if (pending.length === 0)
193
+ return;
194
+ const survivingKeys = new Set(getChanges().map(changeKey));
195
+ let write = 0;
196
+ for (const commit of pending) {
197
+ if (commit.keys.some((key) => survivingKeys.has(key))) {
198
+ pending[write] = commit;
199
+ write += 1;
200
+ continue;
201
+ }
202
+ const { element, property, originalInlineValue, originalInlinePriority } = commit;
203
+ if (originalInlineValue) {
204
+ element.style.setProperty(property, originalInlineValue, originalInlinePriority);
205
+ }
206
+ else {
207
+ element.style.removeProperty(property);
208
+ }
209
+ endLayoutPreview(element, property);
210
+ }
211
+ pending.length = write;
212
+ }
213
+ /** Registers a held preview inline, folding an older unapplied commit for the
214
+ * same element and property into the newest one so the held value and the
215
+ * authored baseline both stay coherent across rapid successive drags. */
216
+ function pushPendingSpacingCommit(pending, next) {
217
+ const existing = pending.findIndex((commit) => commit.iframe === next.iframe
218
+ && commit.element === next.element
219
+ && commit.property === next.property);
220
+ if (existing === -1) {
221
+ pending.push(next);
222
+ return;
223
+ }
224
+ pending[existing] = {
225
+ ...next,
226
+ originalInlineValue: pending[existing].originalInlineValue,
227
+ originalInlinePriority: pending[existing].originalInlinePriority,
228
+ };
229
+ }
135
230
  function sendMeasureModifier(iframe, cardId, altKey) {
136
231
  iframe.contentWindow?.postMessage({
137
232
  type: "measure-modifier",
@@ -148,10 +243,20 @@ export function CanvasElementOverlay() {
148
243
  const [, refreshSelectedGeometry] = useReducer((revision) => revision + 1, 0);
149
244
  const selected = useSelectedElement();
150
245
  const selectedElements = useSelectedElements();
246
+ const hierarchy = useHierarchy();
247
+ const domNavigationEnabled = useNudgeUiRuntimeConfig().capabilities.domNavigation === true;
151
248
  const inlineTextSession = useInlineTextSession();
152
249
  const camera = useBoardCamera();
153
250
  const presentation = useCanvasPresentation();
154
251
  const presentationTransitioning = useCanvasPresentationTransitioning();
252
+ const layoutTransitioning = useCanvasLayoutTransitioning();
253
+ const temporaryAppInteraction = useTemporaryAppInteraction();
254
+ useEffect(() => {
255
+ if (!layoutTransitioning)
256
+ return;
257
+ setHover(null);
258
+ setMeasureState(null);
259
+ }, [layoutTransitioning]);
155
260
  const projectionZoom = presentation === "focus" ? 1 : camera.zoom;
156
261
  const cards = useCanvasCards(); // Projected geometry must follow card drag and resize updates.
157
262
  const cardGeometryKey = cards.map((card) => `${card.id}:${card.x}:${card.y}:${card.width}:${card.height}`).join("|");
@@ -159,6 +264,8 @@ export function CanvasElementOverlay() {
159
264
  const previousProjectionGeometryKey = useRef(projectionGeometryKey);
160
265
  const dragRef = useRef(null);
161
266
  const spacingDragRef = useRef(null);
267
+ const pendingSpacingCommitsRef = useRef([]);
268
+ const [spacingDragBadge, setSpacingDragBadge] = useState(null);
162
269
  const measureAltKeyRef = useRef(false);
163
270
  const dropGuide = useDropGuide("canvas");
164
271
  const projectedDropGuide = projectGuideToCanvas(dropGuide, projectionZoom);
@@ -241,13 +348,56 @@ export function CanvasElementOverlay() {
241
348
  const elementId = el.getAttribute(RENDERER_ELEMENT_ID_ATTR);
242
349
  return elementId ? { elementId } : null;
243
350
  }, [selected?.domElement]);
351
+ // A held spacing preview inline must not outlive the committed rule behind
352
+ // it: undo/redo/revert/clear remove the record synchronously, so restore the
353
+ // authored declaration before the renderer's next replace-styles lands.
354
+ useEffect(() => {
355
+ return subscribeChanges(() => {
356
+ reconcilePendingSpacingCommits(pendingSpacingCommitsRef.current);
357
+ });
358
+ }, []);
244
359
  useEffect(() => {
360
+ const refreshSpacingPreviewOverlay = (drag) => {
361
+ const descriptor = {
362
+ kind: drag.affordance.kind,
363
+ property: drag.affordance.property,
364
+ side: drag.affordance.side,
365
+ };
366
+ const affordance = getSpacingAffordanceForDescriptor(drag.element, descriptor);
367
+ const rect = toRect(drag.element.getBoundingClientRect());
368
+ const borders = readBorderWidths(drag.element);
369
+ const elementId = drag.element.getAttribute(RENDERER_ELEMENT_ID_ATTR);
370
+ setHover((current) => {
371
+ if (!current
372
+ || current.iframe !== drag.iframe
373
+ || current.identity.elementId !== elementId
374
+ || !current.spacing
375
+ || current.spacing.kind !== descriptor.kind
376
+ || current.spacing.property !== descriptor.property
377
+ || current.spacing.side !== descriptor.side) {
378
+ return current;
379
+ }
380
+ return {
381
+ ...current,
382
+ rect,
383
+ borders,
384
+ spacingGuides: affordance?.affectedGuides ?? [],
385
+ spacingAreas: affordance?.affectedAreas ?? [],
386
+ };
387
+ });
388
+ };
245
389
  const unsubscribe = subscribeCanvasRendererMessages(({ cardId: sourceCardId, iframe: sourceIframe, identity: frameIdentity, message: data, }) => {
246
390
  if (data.type === "renderer-hello" || data.type === "frame-ready") {
247
391
  sendMeasureModifier(sourceIframe, sourceCardId, measureAltKeyRef.current);
248
392
  }
249
393
  if (data.type === "renderer-hello")
250
394
  return;
395
+ if (data.type === "projection-applied") {
396
+ releasePendingSpacingCommits(pendingSpacingCommitsRef.current, sourceIframe);
397
+ return;
398
+ }
399
+ if (getCanvasLayoutTransitioning())
400
+ return;
251
401
  if (data.type === "element-hover") {
252
402
  const msg = data;
253
403
  if (!msg.cid)
@@ -256,7 +406,7 @@ export function CanvasElementOverlay() {
256
406
  setHover((current) => current?.cardId === sourceCardId ? null : current);
257
407
  return;
258
408
  }
259
- const spacingDescriptor = msg.spacing ?? null;
409
+ const spacingDescriptor = msg.hoverSpacing ?? msg.spacing ?? null;
260
410
  const hoverPoint = msg.point ?? null;
261
411
  const hoverElement = spacingDescriptor
262
412
  ? findFrameElement(sourceIframe, msg.elementId, msg.cid, msg.src)
@@ -264,7 +414,7 @@ export function CanvasElementOverlay() {
264
414
  const hoverAffordance = spacingDescriptor && hoverElement
265
415
  ? getSpacingAffordanceForDescriptor(hoverElement, spacingDescriptor)
266
416
  : spacingDescriptor && hoverPoint && sourceIframe.contentDocument
267
- ? getSpacingAffordanceAtPoint(sourceIframe.contentDocument, hoverPoint.x, hoverPoint.y)
417
+ ? getSpacingHoverAtPoint(sourceIframe.contentDocument, hoverPoint.x, hoverPoint.y)
268
418
  : null;
269
419
  const matchingAffordance = spacingDescriptorMatches(hoverAffordance, spacingDescriptor)
270
420
  ? hoverAffordance
@@ -321,6 +471,7 @@ export function CanvasElementOverlay() {
321
471
  }
322
472
  else if (data.type === "element-deselect") {
323
473
  clearSpacingDrag(spacingDragRef);
474
+ setSpacingDragBadge(null);
324
475
  dragRef.current = null;
325
476
  clearDropGuide("canvas");
326
477
  setSelectedElement(null);
@@ -357,7 +508,9 @@ export function CanvasElementOverlay() {
357
508
  const selectedElement = resolveSelectionFromElement(element);
358
509
  if (selectedElement)
359
510
  setSelectedElement(selectedElement);
360
- applySpacingPreview(spacingDragRef.current, msg.point);
511
+ applySpacingPreview(spacingDragRef.current, msg.point, msg.shiftKey === true);
512
+ setSpacingDragBadge(spacingBadgeForDrag(spacingDragRef.current, msg.point));
513
+ refreshSpacingPreviewOverlay(spacingDragRef.current);
361
514
  return;
362
515
  }
363
516
  dragRef.current = { iframe: sourceIframe, element };
@@ -369,7 +522,9 @@ export function CanvasElementOverlay() {
369
522
  else if (data.type === "element-drag-move") {
370
523
  const spacing = spacingDragRef.current;
371
524
  if (spacing && spacing.iframe === sourceIframe) {
372
- applySpacingPreview(spacing, data.point);
525
+ applySpacingPreview(spacing, data.point, data.shiftKey === true);
526
+ setSpacingDragBadge(spacingBadgeForDrag(spacing, data.point));
527
+ refreshSpacingPreviewOverlay(spacing);
373
528
  return;
374
529
  }
375
530
  updateDropGuide(data.point, sourceIframe);
@@ -379,12 +534,26 @@ export function CanvasElementOverlay() {
379
534
  const spacing = spacingDragRef.current;
380
535
  if (spacing && spacing.iframe === sourceIframe) {
381
536
  spacingDragRef.current = null;
537
+ setSpacingDragBadge(null);
382
538
  if (msg.cancelled) {
383
539
  restoreSpacingPreview(spacing);
540
+ refreshSpacingPreviewOverlay(spacing);
384
541
  }
385
542
  else {
386
- applySpacingPreview(spacing, msg.point);
387
- commitSpacingDrag(spacing);
543
+ applySpacingPreview(spacing, msg.point, msg.shiftKey === true);
544
+ const records = commitSpacingDrag(spacing);
545
+ if (records.length > 0) {
546
+ pushPendingSpacingCommit(pendingSpacingCommitsRef.current, {
547
+ iframe: sourceIframe,
548
+ element: spacing.element,
549
+ property: spacing.affordance.property,
550
+ committedValue: spacingValueCss(spacing.currentValue),
551
+ keys: records.map((record) => changeKey(record)),
552
+ originalInlineValue: spacing.originalInlineValue,
553
+ originalInlinePriority: spacing.originalInlinePriority,
554
+ });
555
+ }
556
+ refreshSpacingPreviewOverlay(spacing);
388
557
  }
389
558
  clearDropGuide("canvas");
390
559
  if (!msg.cancelled) {
@@ -458,6 +627,7 @@ export function CanvasElementOverlay() {
458
627
  unsubscribe();
459
628
  clearSpacingDrag(spacingDragRef);
460
629
  dragRef.current = null;
630
+ pendingSpacingCommitsRef.current = [];
461
631
  clearDropGuide("canvas");
462
632
  };
463
633
  }, []);
@@ -468,6 +638,9 @@ export function CanvasElementOverlay() {
468
638
  const projectedHoverRect = hover ? projectRect(hover.iframe, hover.rect, projectionZoom) : null;
469
639
  const projectedSpacingGuides = hover?.spacingGuides.map((guide) => projectRect(hover.iframe, guide, projectionZoom)) ?? [];
470
640
  const projectedSpacingAreas = hover?.spacingAreas.map((area) => projectRect(hover.iframe, area, projectionZoom)) ?? [];
641
+ const projectedSpacingBadge = spacingDragBadge
642
+ ? projectPoint(spacingDragBadge.iframe, spacingDragBadge.point.x, spacingDragBadge.point.y, projectionZoom)
643
+ : null;
471
644
  const hoverSpacing = hover?.spacing ?? null;
472
645
  const measureStateForSelectedFrame = measureState?.iframe === selectedFrame ? measureState : null;
473
646
  const hoverInSelectedFrame = hover?.iframe === selectedFrame ? hover : null;
@@ -479,6 +652,9 @@ export function CanvasElementOverlay() {
479
652
  const isSelfHover = Boolean(hoverInSelectedFrame
480
653
  && selectedIdentity
481
654
  && hoverInSelectedFrame.identity.elementId === selectedIdentity.elementId);
655
+ // Selected elements already have a live geometry outline. The hover outline
656
+ // is based on a cached renderer message and can lag during spacing previews.
657
+ const showHoverOutline = Boolean(projectedHoverRect && !isSelfHover);
482
658
  const showMeasurement = Boolean(showGuideOverlay
483
659
  && selectedLocalRect
484
660
  && hoverInSelectedFrame
@@ -489,7 +665,9 @@ export function CanvasElementOverlay() {
489
665
  hoveredBorders: hoverInSelectedFrame.borders,
490
666
  }).segments, projectionZoom)
491
667
  : [];
492
- if (presentationTransitioning)
668
+ if (presentationTransitioning || layoutTransitioning || temporaryAppInteraction)
493
669
  return _jsx("style", { "data-test": "canvas-element-overlay-styles", children: overlayStyles });
494
- return (_jsxs(_Fragment, { children: [_jsx("style", { "data-test": "canvas-element-overlay-styles", children: overlayStyles }), showGuideOverlay && selectedRect && selectedFrameRect ? (_jsx(MeasurementGuideOverlay, { testId: "canvas-measurement-overlay", selectedRect: selectedRect, guideViewport: selectedFrameRect, segments: measurementSegments })) : null, projectedHoverRect ? (_jsxs(_Fragment, { children: [hoverSpacing ? projectedSpacingAreas.map((area, index) => (_jsx("div", { className: "canvas-spacing-fill", "data-test": "canvas-spacing-fill", "data-kind": hoverSpacing.kind, "data-property": hoverSpacing.property, "data-side": hoverSpacing.side ?? undefined, "data-area-index": index, style: overlayStyle(area), "aria-hidden": "true" }, `${hoverSpacing.property}-area-${index}`))) : null, _jsx("div", { className: "canvas-element-overlay", "data-test": "canvas-hover-outline", style: overlayStyle(projectedHoverRect), "aria-hidden": "true" }), hoverSpacing ? projectedSpacingGuides.map((guide, index) => (_jsx("div", { className: "canvas-spacing-guide", "data-test": "canvas-spacing-guide", "data-kind": hoverSpacing.kind, "data-property": hoverSpacing.property, "data-side": hoverSpacing.side ?? undefined, "data-guide-index": index, style: spacingGuideStyle(guide), "aria-hidden": "true" }, `${hoverSpacing.property}-${index}`))) : null] })) : null, projectedSelectedGeometry.map(({ element, rect }, index) => (_jsx("div", { className: "canvas-selected-outline", "data-test": "canvas-selected-outline", "data-selected-cid": element.cid, "data-selected-index": index, "data-selected-src": element.src, style: overlayStyle(rect), "aria-hidden": "true" }, `${element.cid}-${index}`))), _jsx(DropGuideOverlay, { guide: projectedDropGuide, lineClassName: "canvas-dom-drop-line", lineTestId: "canvas-dom-drop-line", targetClassName: "canvas-dom-drop-target", targetTestId: "canvas-dom-drop-target" })] }));
670
+ return (_jsxs(_Fragment, { children: [_jsx("style", { "data-test": "canvas-element-overlay-styles", children: overlayStyles }), showGuideOverlay && selectedRect && selectedFrameRect ? (_jsx(MeasurementGuideOverlay, { testId: "canvas-measurement-overlay", selectedRect: selectedRect, guideViewport: selectedFrameRect, segments: measurementSegments })) : null, projectedHoverRect ? (_jsxs(_Fragment, { children: [hoverSpacing ? projectedSpacingAreas.map((area, index) => (_jsx("div", { className: "canvas-spacing-fill", "data-test": "canvas-spacing-fill", "data-kind": hoverSpacing.kind, "data-property": hoverSpacing.property, "data-side": hoverSpacing.side ?? undefined, "data-area-index": index, style: overlayStyle(area), "aria-hidden": "true" }, `${hoverSpacing.property}-area-${index}`))) : null, showHoverOutline ? (_jsx("div", { className: "canvas-element-overlay", "data-test": "canvas-hover-outline", style: overlayStyle(projectedHoverRect), "aria-hidden": "true" })) : null, hoverSpacing ? projectedSpacingGuides.map((guide, index) => (_jsx("div", { className: "canvas-spacing-guide", "data-test": "canvas-spacing-guide", "data-kind": hoverSpacing.kind, "data-property": hoverSpacing.property, "data-side": hoverSpacing.side ?? undefined, "data-guide-index": index, style: spacingGuideStyle(guide), "aria-hidden": "true" }, `${hoverSpacing.property}-${index}`))) : null] })) : null, projectedSelectedGeometry.map(({ element, rect }, index) => (_jsx("div", { className: "canvas-selected-outline", "data-test": "canvas-selected-outline", "data-selected-cid": element.cid, "data-selected-index": index, "data-selected-src": element.src, style: overlayStyle(rect), "aria-hidden": "true" }, `${element.cid}-${index}`))), projectedSpacingBadge && spacingDragBadge ? (_jsx("div", { className: "canvas-spacing-value-badge", "data-test": "canvas-spacing-value-badge", style: { left: projectedSpacingBadge.x, top: projectedSpacingBadge.y }, "aria-hidden": "true", children: spacingValueCss(spacingDragBadge.value) })) : null, domNavigationEnabled && !inlineTextSession && selectedElements.length === 1 && selected && selectedRect && selectedFrame instanceof HTMLIFrameElement ? (_jsx(DomNavigator, { selected: selected, hierarchy: hierarchy, anchor: selectedRect, project: (element) => element.ownerDocument === selected.domElement.ownerDocument
671
+ ? projectRect(selectedFrame, toRect(element.getBoundingClientRect()), projectionZoom)
672
+ : null })) : null, _jsx(DropGuideOverlay, { guide: projectedDropGuide, lineClassName: "canvas-dom-drop-line", lineTestId: "canvas-dom-drop-line", targetClassName: "canvas-dom-drop-target", targetTestId: "canvas-dom-drop-target" })] }));
495
673
  }
@@ -0,0 +1,10 @@
1
+ import type { ReactElement, SVGProps } from "react";
2
+ type CanvasToolIconProps = Pick<SVGProps<SVGSVGElement>, "aria-hidden" | "className" | "style"> & {
3
+ readonly size?: string | number;
4
+ };
5
+ export declare function DesignPointerFilledIcon(props: CanvasToolIconProps): ReactElement;
6
+ export declare function SketchThickIcon(props: CanvasToolIconProps): ReactElement;
7
+ export declare function PanHandFilledIcon(props: CanvasToolIconProps): ReactElement;
8
+ export declare function SelectPlayOutlineIcon(props: CanvasToolIconProps): ReactElement;
9
+ export declare function SelectPlayFilledIcon(props: CanvasToolIconProps): ReactElement;
10
+ export {};
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ function ToolIconSvg({ size = 24, children, ...props }) {
3
+ return (_jsx("svg", { viewBox: "0 0 24 24", width: size, height: size, fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: children }));
4
+ }
5
+ export function DesignPointerFilledIcon(props) {
6
+ return (_jsx(ToolIconSvg, { ...props, children: _jsx("path", { d: "M19.8289 10.9379L14.499 12.9999L14.1844 13.1399C13.9474 13.2324 13.7322 13.373 13.5524 13.5529C13.3725 13.7327 13.2319 13.9479 13.1395 14.1849L10.9376 19.8288C10.3047 21.4538 7.97489 21.3668 7.46494 19.6988L3.08331 5.38099C2.65134 3.97101 3.97123 2.65202 5.38111 3.08302L19.6989 7.46496C21.3668 7.97595 21.4537 10.3039 19.8289 10.9379Z", fill: "currentColor" }) }));
7
+ }
8
+ export function SketchThickIcon(props) {
9
+ return (_jsx(ToolIconSvg, { ...props, children: _jsx("path", { d: "M4 15C6 10.03 11.356 4 13 4C17.25 4 7.5 15.958 10 17C12.5 18.042 15.65 10.322 17.4 11.098C19.15 11.875 16.35 18.687 17.1 19.728C17.85 20.769 20.25 18.831 21 17", stroke: "currentColor", strokeWidth: 3, strokeLinecap: "round", strokeLinejoin: "round" }) }));
10
+ }
11
+ export function PanHandFilledIcon(props) {
12
+ return (_jsx(ToolIconSvg, { ...props, children: _jsx("path", { d: "M12.5 2.5C12.6312 2.50003 12.7616 2.52599 12.8828 2.57617C13.004 2.6264 13.1143 2.70024 13.207 2.79297C13.2998 2.88575 13.3736 2.99599 13.4238 3.11719C13.4741 3.23849 13.5 3.36871 13.5 3.5V12C13.5 12.2761 13.724 12.4999 14 12.5C14.2761 12.4999 14.5 12.2761 14.5 12V5.5C14.5 5.23483 14.6055 4.98049 14.793 4.79297C14.9805 4.60555 15.2349 4.50006 15.5 4.5C15.7651 4.50006 16.0196 4.60555 16.207 4.79297C16.3945 4.98049 16.5 5.23484 16.5 5.5V12C16.5 12.2761 16.724 12.4999 17 12.5C17.2761 12.4999 17.5 12.2761 17.5 12V7.5C17.5 7.23483 17.6055 6.9805 17.793 6.79297C17.9805 6.60555 18.2349 6.50006 18.5 6.5C18.7651 6.50006 19.0196 6.60555 19.207 6.79297C19.3945 6.98049 19.5 7.23484 19.5 7.5V16C19.5 17.4585 18.9208 18.8573 17.8897 19.8887C16.8583 20.9201 15.4586 21.4999 14 21.5H12.208C11.2973 21.5001 10.4005 21.2737 9.59865 20.8418C8.79689 20.4098 8.11519 19.786 7.61427 19.0254C7.54921 18.9264 7.48351 18.8269 7.41896 18.7275C7.11837 18.266 6.03484 16.376 4.15041 13.0264C4.0228 12.7994 3.98801 12.5319 4.0547 12.2803C4.12142 12.0287 4.28463 11.8126 4.50783 11.6787C4.7689 11.5222 5.07483 11.4571 5.37697 11.4941C5.67933 11.5313 5.96123 11.6685 6.17677 11.8838L7.6465 13.3535C7.68032 13.3873 7.71897 13.4135 7.7588 13.4355C7.80294 13.4601 7.85033 13.48 7.90138 13.4902C7.96605 13.5031 8.03299 13.5031 8.09767 13.4902C8.15175 13.4795 8.20178 13.4583 8.24806 13.4316C8.28533 13.4102 8.32167 13.3854 8.35353 13.3535C8.38754 13.3195 8.41341 13.2803 8.43556 13.2402C8.46003 13.196 8.48011 13.1488 8.49025 13.0977C8.49663 13.0654 8.50002 13.0327 8.50002 13V5.5C8.50002 5.23483 8.60551 4.98049 8.79298 4.79297C8.98046 4.60555 9.23493 4.50006 9.50002 4.5C9.7651 4.50006 10.0196 4.60555 10.207 4.79297C10.3945 4.98049 10.5 5.23484 10.5 5.5V12C10.5 12.2761 10.724 12.4999 11 12.5C11.2761 12.4999 11.5 12.2761 11.5 12V3.5C11.5 3.3687 11.526 3.23849 11.5762 3.11719C11.6264 2.99599 11.7002 2.88575 11.793 2.79297C11.8857 2.70024 11.996 2.6264 12.1172 2.57617C12.2384 2.526 12.3688 2.50003 12.5 2.5Z", fill: "currentColor" }) }));
13
+ }
14
+ const SELECT_PLAY_PATH = "M8.5241 4.93791C7.85783 4.52789 7 5.00724 7 5.78956V18.2104C7 18.9928 7.85783 19.4721 8.5241 19.0621L18.6161 12.8517C19.2506 12.4612 19.2506 11.5388 18.6161 11.1483L8.5241 4.93791Z";
15
+ export function SelectPlayOutlineIcon(props) {
16
+ return (_jsx(ToolIconSvg, { ...props, children: _jsx("path", { d: SELECT_PLAY_PATH, stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" }) }));
17
+ }
18
+ export function SelectPlayFilledIcon(props) {
19
+ return (_jsx(ToolIconSvg, { ...props, children: _jsx("path", { d: SELECT_PLAY_PATH, fill: "currentColor", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) }));
20
+ }
@@ -1,6 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconHandStop, IconPointer2, IconSketching, } from "@tabler/icons-react";
2
+ import { IconMessageCircle, IconMessageCircleFilled, IconPointer2, IconSketching } from "@tabler/icons-react";
3
3
  import { IconButton } from "../ui/IconButton.js";
4
+ import { Tooltip } from "../ui/Tooltip.js";
5
+ import { DesignPointerFilledIcon, SelectPlayFilledIcon, SelectPlayOutlineIcon, SketchThickIcon, } from "./CanvasToolIcons.js";
4
6
  export const CANVAS_ZOOM_LEVELS = [0.25, 0.5, 0.9, 1];
5
7
  export function closestCanvasZoomLevel(zoom) {
6
8
  let closest = CANVAS_ZOOM_LEVELS[0];
@@ -16,9 +18,11 @@ export function adjacentCanvasZoomLevel(zoom, direction) {
16
18
  const next = CANVAS_ZOOM_LEVELS[index + direction];
17
19
  return next === undefined ? null : next;
18
20
  }
19
- function ToolButton({ active, disabled, label, icon, onClick, }) {
20
- return (_jsx(IconButton, { variant: "quiet", size: "large", className: "canvas-toolbar__tool", label: label, title: label, "aria-pressed": active, "data-test": `canvas-tool-${label.toLowerCase()}`, "data-active": active ? "true" : "false", disabled: disabled, onClick: onClick, children: icon }));
21
+ const ICON_SIZE = "var(--icon-size-large)";
22
+ function ToolButton({ tool, activeTool, disabled, label, shortcut, icon, activeIcon, onToolChange, }) {
23
+ const active = tool === activeTool;
24
+ return (_jsx(Tooltip, { content: label, shortcut: shortcut, stableTrigger: true, children: _jsx(IconButton, { variant: "quiet", size: "large", className: "canvas-toolbar__tool", label: label, "aria-pressed": active, "data-test": `canvas-tool-${tool}`, "data-active": active ? "true" : "false", disabled: disabled, onClick: () => onToolChange(tool), children: active ? activeIcon : icon }) }));
21
25
  }
22
26
  export function CanvasToolbar({ tool, sketchEnabled, onToolChange, }) {
23
- return (_jsx("div", { className: "canvas-toolbar", "data-test": "canvas-toolbar", role: "toolbar", "aria-label": "Canvas tools", children: _jsxs("div", { className: "canvas-toolbar__tools", role: "group", "aria-label": "Interaction tools", children: [_jsx(ToolButton, { active: tool === "move", label: "Move", icon: _jsx(IconPointer2, { size: "var(--icon-size-large)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), onClick: () => onToolChange("move") }), _jsx(ToolButton, { active: tool === "pan", label: "Pan", icon: _jsx(IconHandStop, { size: "var(--icon-size-large)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), onClick: () => onToolChange("pan") }), _jsx(ToolButton, { active: tool === "sketch", label: "Sketch", disabled: !sketchEnabled, icon: _jsx(IconSketching, { size: "var(--icon-size-large)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), onClick: () => onToolChange("sketch") })] }) }));
27
+ return (_jsxs("div", { className: "canvas-toolbar", "data-test": "canvas-toolbar", role: "toolbar", "aria-label": "Canvas tools", children: [_jsxs("div", { className: "canvas-toolbar__tools", role: "group", "aria-label": "Interaction tools", children: [_jsx(ToolButton, { tool: "design", activeTool: tool, label: "Select", shortcut: "V", icon: _jsx(IconPointer2, { size: ICON_SIZE, stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), activeIcon: _jsx(DesignPointerFilledIcon, { size: ICON_SIZE, "aria-hidden": "true" }), onToolChange: onToolChange }), _jsx(ToolButton, { tool: "comment", activeTool: tool, label: "Comment", shortcut: "C", icon: _jsx(IconMessageCircle, { size: ICON_SIZE, stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), activeIcon: _jsx(IconMessageCircleFilled, { size: ICON_SIZE, "aria-hidden": "true" }), onToolChange: onToolChange }), _jsx(ToolButton, { tool: "sketch", activeTool: tool, label: "Pencil", shortcut: "P", disabled: !sketchEnabled, icon: _jsx(IconSketching, { size: ICON_SIZE, stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), activeIcon: _jsx(SketchThickIcon, { size: ICON_SIZE, "aria-hidden": "true" }), onToolChange: onToolChange })] }), _jsx("div", { className: "canvas-toolbar__divider", "aria-hidden": "true" }), _jsx("div", { className: "canvas-toolbar__tools", role: "group", "aria-label": "Preview tools", children: _jsx(ToolButton, { tool: "select", activeTool: tool, label: "Use app normally", shortcut: "Hold A", icon: _jsx(SelectPlayOutlineIcon, { size: ICON_SIZE, "aria-hidden": "true" }), activeIcon: _jsx(SelectPlayFilledIcon, { size: ICON_SIZE, "aria-hidden": "true" }), onToolChange: onToolChange }) })] }));
24
28
  }