nudge-ui 0.2.2 → 0.2.4

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 (244) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +260 -61
  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 +38 -32
  7. package/dist/hosts/astro/integration.js +5 -1
  8. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  9. package/dist/hosts/astro/markdownIdentity.js +81 -0
  10. package/dist/hosts/next/manifest.js +1 -1
  11. package/dist/hosts/next/sidecar.js +5 -1
  12. package/dist/hosts/static/manifest.js +1 -1
  13. package/dist/hosts/static/server.js +3 -0
  14. package/dist/hosts/vite/vite.d.ts +3 -0
  15. package/dist/hosts/vite/vite.js +24 -4
  16. package/dist/inspector/agent/McpConnectionDialog.js +13 -19
  17. package/dist/inspector/agent/activity.d.ts +18 -0
  18. package/dist/inspector/agent/activity.js +70 -0
  19. package/dist/inspector/agent/client.d.ts +2 -0
  20. package/dist/inspector/agent/client.js +29 -1
  21. package/dist/inspector/agent/connectionStatus.js +1 -1
  22. package/dist/inspector/agent/httpTransport.js +9 -2
  23. package/dist/inspector/agent/protocol.d.ts +6 -3
  24. package/dist/inspector/agent/protocol.js +1 -1
  25. package/dist/inspector/agent/verification.d.ts +15 -7
  26. package/dist/inspector/agent/verification.js +113 -41
  27. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  28. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  29. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  30. package/dist/inspector/canvas/CanvasCard.js +135 -38
  31. package/dist/inspector/canvas/CanvasElementOverlay.js +166 -16
  32. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  33. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  34. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  35. package/dist/inspector/canvas/CanvasWorkspace.js +270 -122
  36. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  37. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  38. package/dist/inspector/canvas/agentPresentation.js +64 -52
  39. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  40. package/dist/inspector/canvas/canvasGestures.js +1 -1
  41. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  42. package/dist/inspector/canvas/canvasStore.js +251 -284
  43. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  44. package/dist/inspector/canvas/frameContent.js +44 -0
  45. package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
  46. package/dist/inspector/canvas/frameProtocol.js +3 -3
  47. package/dist/inspector/canvas/frameScrollbarStyles.d.ts +3 -0
  48. package/dist/inspector/canvas/frameScrollbarStyles.js +21 -0
  49. package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
  50. package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
  51. package/dist/inspector/canvas/layout.d.ts +52 -0
  52. package/dist/inspector/canvas/layout.js +106 -0
  53. package/dist/inspector/canvas/projection.d.ts +15 -5
  54. package/dist/inspector/canvas/projection.js +69 -13
  55. package/dist/inspector/canvas/rendererBootstrap.js +32 -4
  56. package/dist/inspector/canvas/rendererElementSelector.js +47 -6
  57. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  58. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  59. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  60. package/dist/inspector/canvas/sessionStore.js +43 -183
  61. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  62. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  63. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  64. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  65. package/dist/inspector/canvas/viewStore.js +104 -0
  66. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  67. package/dist/inspector/canvas/wheelPan.js +8 -0
  68. package/dist/inspector/changes/changesLog.d.ts +9 -6
  69. package/dist/inspector/changes/changesLog.js +48 -32
  70. package/dist/inspector/changes/codecs.d.ts +1 -0
  71. package/dist/inspector/changes/codecs.js +10 -1
  72. package/dist/inspector/changes/draftChanges.d.ts +58 -0
  73. package/dist/inspector/changes/draftChanges.js +304 -0
  74. package/dist/inspector/changes/editModel.d.ts +10 -0
  75. package/dist/inspector/changes/editModel.js +9 -2
  76. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  77. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  78. package/dist/inspector/changes/types.d.ts +7 -0
  79. package/dist/inspector/clientManifest.d.ts +1 -1
  80. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  81. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  82. package/dist/inspector/comments/element.d.ts +6 -0
  83. package/dist/inspector/comments/element.js +54 -0
  84. package/dist/inspector/comments/store.d.ts +29 -0
  85. package/dist/inspector/comments/store.js +121 -0
  86. package/dist/inspector/comments/verification.d.ts +5 -0
  87. package/dist/inspector/comments/verification.js +52 -0
  88. package/dist/inspector/componentSemantics/adapterRegistry.d.ts +6 -1
  89. package/dist/inspector/componentSemantics/adapterRegistry.js +23 -1
  90. package/dist/inspector/componentSemantics/reactRuntime.d.ts +2 -1
  91. package/dist/inspector/componentSemantics/reactRuntime.js +38 -0
  92. package/dist/inspector/componentSemantics/runtimeBridge.d.ts +4 -2
  93. package/dist/inspector/componentSemantics/runtimeBridge.js +17 -0
  94. package/dist/inspector/componentSemantics/types.d.ts +11 -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 +20 -27
  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 +174 -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.js +21 -15
  111. package/dist/inspector/overlay/interactionStyles.js +3 -1
  112. package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
  113. package/dist/inspector/overlay/spacingGestures.js +82 -5
  114. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  115. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  116. package/dist/inspector/projection/renderedInstance.d.ts +17 -3
  117. package/dist/inspector/projection/renderedInstance.js +62 -11
  118. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  119. package/dist/inspector/projection/structuralProjection.js +21 -17
  120. package/dist/inspector/projection/textProjection.d.ts +2 -1
  121. package/dist/inspector/projection/textProjection.js +64 -15
  122. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  123. package/dist/inspector/prompt/clipboardHandoff.d.ts +15 -18
  124. package/dist/inspector/prompt/clipboardHandoff.js +97 -143
  125. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  126. package/dist/inspector/prompt/generatePrompt.js +22 -17
  127. package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
  128. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  129. package/dist/inspector/selection/sourceSite.d.ts +12 -0
  130. package/dist/inspector/selection/sourceSite.js +28 -0
  131. package/dist/inspector/settings/SettingsDialog.js +21 -8
  132. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  133. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  134. package/dist/inspector/shell/AppShell.js +4 -2
  135. package/dist/inspector/shell/ChangesLog.js +46 -26
  136. package/dist/inspector/shell/CopyPromptButton.js +184 -93
  137. package/dist/inspector/shell/EmptyState.js +9 -8
  138. package/dist/inspector/shell/InspectorShell.js +13 -21
  139. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  140. package/dist/inspector/shell/originalPreview.js +5 -5
  141. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  142. package/dist/inspector/shell/shortcuts.js +11 -0
  143. package/dist/inspector/sketch/SketchEditor.js +14 -14
  144. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  145. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  146. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  147. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  148. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  149. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  150. package/dist/inspector/sketch/interaction.d.ts +1 -0
  151. package/dist/inspector/sketch/interaction.js +8 -4
  152. package/dist/inspector/sketch/model.d.ts +5 -0
  153. package/dist/inspector/sketch/model.js +6 -2
  154. package/dist/inspector/sketch/raster.d.ts +1 -2
  155. package/dist/inspector/sketch/raster.js +68 -4
  156. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  157. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  158. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  159. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  160. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  161. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  162. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  163. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  164. package/dist/inspector/styleEditors/GapField.js +3 -5
  165. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  166. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  167. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  168. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  169. package/dist/inspector/styleEditors/GridSection.js +1 -1
  170. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  171. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  172. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  173. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  174. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  175. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  176. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  177. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  178. package/dist/inspector/styleEditors/SpacingBox.js +7 -5
  179. package/dist/inspector/styleEditors/Typography.js +11 -3
  180. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  181. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  182. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  183. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  184. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  185. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  186. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  187. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  188. package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
  189. package/dist/inspector/styleEditors/nudgeValue.js +36 -8
  190. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  191. package/dist/inspector/tokens/TokenField.js +35 -25
  192. package/dist/inspector/tokens/TokenLabel.js +5 -14
  193. package/dist/inspector/tokens/editActions.d.ts +1 -1
  194. package/dist/inspector/tokens/editActions.js +7 -1
  195. package/dist/inspector/ui/AtRuleContext.js +4 -6
  196. package/dist/inspector/ui/Button.d.ts +6 -2
  197. package/dist/inspector/ui/Button.js +4 -3
  198. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  199. package/dist/inspector/ui/ControlSurface.js +4 -3
  200. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  201. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  202. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  203. package/dist/inspector/ui/InspectorPopover.js +4 -5
  204. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  205. package/dist/inspector/ui/PopoverListbox.js +8 -7
  206. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  207. package/dist/inspector/ui/SegmentedControl.js +2 -2
  208. package/dist/inspector/ui/Select.d.ts +6 -1
  209. package/dist/inspector/ui/Select.js +7 -11
  210. package/dist/inspector/ui/SideValuesField.js +1 -1
  211. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  212. package/dist/inspector/ui/Tooltip.js +32 -0
  213. package/dist/inspector/ui/classNames.d.ts +2 -0
  214. package/dist/inspector/ui/classNames.js +4 -0
  215. package/dist/inspector/ui/customCursors.d.ts +23 -0
  216. package/dist/inspector/ui/customCursors.js +122 -0
  217. package/dist/inspector/ui/dragCursor.d.ts +0 -2
  218. package/dist/inspector/ui/dragCursor.js +2 -10
  219. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  220. package/dist/inspector/ui/portalContainer.js +6 -0
  221. package/dist/inspector/ui/styles.js +29 -21
  222. package/dist/inspector/workspace/commands.d.ts +9 -0
  223. package/dist/inspector/workspace/commands.js +82 -0
  224. package/dist/inspector/workspace/controller.d.ts +4 -0
  225. package/dist/inspector/workspace/controller.js +66 -0
  226. package/dist/inspector/workspace/handoff.d.ts +42 -0
  227. package/dist/inspector/workspace/handoff.js +115 -0
  228. package/dist/inspector/workspace/sentItems.d.ts +19 -0
  229. package/dist/inspector/workspace/sentItems.js +51 -0
  230. package/dist/inspector/workspace/timeline.d.ts +30 -0
  231. package/dist/inspector/workspace/timeline.js +108 -0
  232. package/dist/internal/agent-protocol.d.ts +19 -2
  233. package/dist/internal/agent-protocol.js +13 -0
  234. package/dist/nudge-ui.mjs +558 -311
  235. package/dist/project/artifacts.d.ts +13 -0
  236. package/dist/project/artifacts.js +253 -0
  237. package/dist/transport/artifacts.d.ts +8 -0
  238. package/dist/transport/artifacts.js +9 -0
  239. package/dist/transport/editor.js +3 -1
  240. package/dist/transport/routes.d.ts +2 -0
  241. package/dist/transport/routes.js +2 -0
  242. package/package.json +7 -3
  243. package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
  244. package/dist/inspector/changes/workspaceChanges.js +0 -265
@@ -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
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,7 +26,7 @@ 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";
28
31
  import { useNudgeUiRuntimeConfig } from "../runtime/useRuntimeConfig.js";
29
32
  import { DomNavigator } from "../overlay/DomNavigator.js";
@@ -36,6 +39,20 @@ function projectRect(iframe, rect, zoom) {
36
39
  height: rect.height * zoom,
37
40
  };
38
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
+ }
39
56
  function overlayStyle(rect) {
40
57
  return {
41
58
  position: "fixed",
@@ -121,19 +138,95 @@ function restoreSpacingPreview(drag) {
121
138
  }
122
139
  endLayoutPreview(drag.element, drag.affordance.property);
123
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
+ */
124
149
  function commitSpacingDrag(drag) {
125
- // Restore the authored declaration before committing the managed rule. The
126
- // captured start value is the baseline because the pointer remains hovered
127
- // and CSS inspection can still report the transient preview value.
128
- restoreSpacingPreview(drag);
129
- if (drag.currentValue === drag.startValue)
130
- return;
131
- setStyles(drag.element, [{
150
+ if (drag.currentValue === drag.startValue) {
151
+ restoreSpacingPreview(drag);
152
+ return [];
153
+ }
154
+ return setStyles(drag.element, [{
132
155
  property: drag.affordance.property,
133
156
  value: spacingValueCss(drag.currentValue),
134
157
  oldRawValue: spacingValueCss(drag.startValue),
135
158
  }]);
136
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
+ }
137
230
  function sendMeasureModifier(iframe, cardId, altKey) {
138
231
  iframe.contentWindow?.postMessage({
139
232
  type: "measure-modifier",
@@ -156,6 +249,14 @@ export function CanvasElementOverlay() {
156
249
  const camera = useBoardCamera();
157
250
  const presentation = useCanvasPresentation();
158
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]);
159
260
  const projectionZoom = presentation === "focus" ? 1 : camera.zoom;
160
261
  const cards = useCanvasCards(); // Projected geometry must follow card drag and resize updates.
161
262
  const cardGeometryKey = cards.map((card) => `${card.id}:${card.x}:${card.y}:${card.width}:${card.height}`).join("|");
@@ -163,6 +264,8 @@ export function CanvasElementOverlay() {
163
264
  const previousProjectionGeometryKey = useRef(projectionGeometryKey);
164
265
  const dragRef = useRef(null);
165
266
  const spacingDragRef = useRef(null);
267
+ const pendingSpacingCommitsRef = useRef([]);
268
+ const [spacingDragBadge, setSpacingDragBadge] = useState(null);
166
269
  const measureAltKeyRef = useRef(false);
167
270
  const dropGuide = useDropGuide("canvas");
168
271
  const projectedDropGuide = projectGuideToCanvas(dropGuide, projectionZoom);
@@ -245,6 +348,14 @@ export function CanvasElementOverlay() {
245
348
  const elementId = el.getAttribute(RENDERER_ELEMENT_ID_ATTR);
246
349
  return elementId ? { elementId } : null;
247
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
+ }, []);
248
359
  useEffect(() => {
249
360
  const refreshSpacingPreviewOverlay = (drag) => {
250
361
  const descriptor = {
@@ -272,6 +383,9 @@ export function CanvasElementOverlay() {
272
383
  borders,
273
384
  spacingGuides: affordance?.affectedGuides ?? [],
274
385
  spacingAreas: affordance?.affectedAreas ?? [],
386
+ spacingHandleBadge: current.spacingHandleBadge && affordance
387
+ ? { ...current.spacingHandleBadge, value: affordance.value }
388
+ : current.spacingHandleBadge,
275
389
  };
276
390
  });
277
391
  };
@@ -281,6 +395,12 @@ export function CanvasElementOverlay() {
281
395
  }
282
396
  if (data.type === "renderer-hello")
283
397
  return;
398
+ if (data.type === "projection-applied") {
399
+ releasePendingSpacingCommits(pendingSpacingCommitsRef.current, sourceIframe);
400
+ return;
401
+ }
402
+ if (getCanvasLayoutTransitioning())
403
+ return;
284
404
  if (data.type === "element-hover") {
285
405
  const msg = data;
286
406
  if (!msg.cid)
@@ -289,7 +409,7 @@ export function CanvasElementOverlay() {
289
409
  setHover((current) => current?.cardId === sourceCardId ? null : current);
290
410
  return;
291
411
  }
292
- const spacingDescriptor = msg.spacing ?? null;
412
+ const spacingDescriptor = msg.hoverSpacing ?? msg.spacing ?? null;
293
413
  const hoverPoint = msg.point ?? null;
294
414
  const hoverElement = spacingDescriptor
295
415
  ? findFrameElement(sourceIframe, msg.elementId, msg.cid, msg.src)
@@ -297,13 +417,21 @@ export function CanvasElementOverlay() {
297
417
  const hoverAffordance = spacingDescriptor && hoverElement
298
418
  ? getSpacingAffordanceForDescriptor(hoverElement, spacingDescriptor)
299
419
  : spacingDescriptor && hoverPoint && sourceIframe.contentDocument
300
- ? getSpacingAffordanceAtPoint(sourceIframe.contentDocument, hoverPoint.x, hoverPoint.y)
420
+ ? getSpacingHoverAtPoint(sourceIframe.contentDocument, hoverPoint.x, hoverPoint.y)
301
421
  : null;
302
422
  const matchingAffordance = spacingDescriptorMatches(hoverAffordance, spacingDescriptor)
303
423
  ? hoverAffordance
304
424
  : null;
305
425
  const spacingGuides = matchingAffordance?.affectedGuides ?? [];
306
426
  const spacingAreas = matchingAffordance?.affectedAreas ?? [];
427
+ const handleAffordance = msg.spacing && hoverElement
428
+ ? getSpacingAffordanceForDescriptor(hoverElement, msg.spacing)
429
+ : null;
430
+ const spacingHandleBadge = hoverPoint
431
+ && handleAffordance
432
+ && spacingDescriptorMatches(handleAffordance, msg.spacing)
433
+ ? { point: hoverPoint, value: handleAffordance.value }
434
+ : null;
307
435
  setHover({
308
436
  iframe: sourceIframe,
309
437
  identity: { elementId: msg.elementId },
@@ -313,6 +441,7 @@ export function CanvasElementOverlay() {
313
441
  spacing: spacingGuides.length > 0 ? spacingDescriptor : null,
314
442
  spacingGuides,
315
443
  spacingAreas,
444
+ spacingHandleBadge,
316
445
  });
317
446
  }
318
447
  else if (data.type === "element-measure-state") {
@@ -354,6 +483,7 @@ export function CanvasElementOverlay() {
354
483
  }
355
484
  else if (data.type === "element-deselect") {
356
485
  clearSpacingDrag(spacingDragRef);
486
+ setSpacingDragBadge(null);
357
487
  dragRef.current = null;
358
488
  clearDropGuide("canvas");
359
489
  setSelectedElement(null);
@@ -391,6 +521,7 @@ export function CanvasElementOverlay() {
391
521
  if (selectedElement)
392
522
  setSelectedElement(selectedElement);
393
523
  applySpacingPreview(spacingDragRef.current, msg.point, msg.shiftKey === true);
524
+ setSpacingDragBadge(spacingBadgeForDrag(spacingDragRef.current, msg.point));
394
525
  refreshSpacingPreviewOverlay(spacingDragRef.current);
395
526
  return;
396
527
  }
@@ -404,6 +535,7 @@ export function CanvasElementOverlay() {
404
535
  const spacing = spacingDragRef.current;
405
536
  if (spacing && spacing.iframe === sourceIframe) {
406
537
  applySpacingPreview(spacing, data.point, data.shiftKey === true);
538
+ setSpacingDragBadge(spacingBadgeForDrag(spacing, data.point));
407
539
  refreshSpacingPreviewOverlay(spacing);
408
540
  return;
409
541
  }
@@ -414,13 +546,25 @@ export function CanvasElementOverlay() {
414
546
  const spacing = spacingDragRef.current;
415
547
  if (spacing && spacing.iframe === sourceIframe) {
416
548
  spacingDragRef.current = null;
549
+ setSpacingDragBadge(null);
417
550
  if (msg.cancelled) {
418
551
  restoreSpacingPreview(spacing);
419
552
  refreshSpacingPreviewOverlay(spacing);
420
553
  }
421
554
  else {
422
555
  applySpacingPreview(spacing, msg.point, msg.shiftKey === true);
423
- commitSpacingDrag(spacing);
556
+ const records = commitSpacingDrag(spacing);
557
+ if (records.length > 0) {
558
+ pushPendingSpacingCommit(pendingSpacingCommitsRef.current, {
559
+ iframe: sourceIframe,
560
+ element: spacing.element,
561
+ property: spacing.affordance.property,
562
+ committedValue: spacingValueCss(spacing.currentValue),
563
+ keys: records.map((record) => changeKey(record)),
564
+ originalInlineValue: spacing.originalInlineValue,
565
+ originalInlinePriority: spacing.originalInlinePriority,
566
+ });
567
+ }
424
568
  refreshSpacingPreviewOverlay(spacing);
425
569
  }
426
570
  clearDropGuide("canvas");
@@ -495,6 +639,7 @@ export function CanvasElementOverlay() {
495
639
  unsubscribe();
496
640
  clearSpacingDrag(spacingDragRef);
497
641
  dragRef.current = null;
642
+ pendingSpacingCommitsRef.current = [];
498
643
  clearDropGuide("canvas");
499
644
  };
500
645
  }, []);
@@ -505,6 +650,11 @@ export function CanvasElementOverlay() {
505
650
  const projectedHoverRect = hover ? projectRect(hover.iframe, hover.rect, projectionZoom) : null;
506
651
  const projectedSpacingGuides = hover?.spacingGuides.map((guide) => projectRect(hover.iframe, guide, projectionZoom)) ?? [];
507
652
  const projectedSpacingAreas = hover?.spacingAreas.map((area) => projectRect(hover.iframe, area, projectionZoom)) ?? [];
653
+ const spacingBadge = spacingDragBadge
654
+ ?? (hover?.spacingHandleBadge ? { iframe: hover.iframe, ...hover.spacingHandleBadge } : null);
655
+ const projectedSpacingBadge = spacingBadge
656
+ ? projectPoint(spacingBadge.iframe, spacingBadge.point.x, spacingBadge.point.y, projectionZoom)
657
+ : null;
508
658
  const hoverSpacing = hover?.spacing ?? null;
509
659
  const measureStateForSelectedFrame = measureState?.iframe === selectedFrame ? measureState : null;
510
660
  const hoverInSelectedFrame = hover?.iframe === selectedFrame ? hover : null;
@@ -529,9 +679,9 @@ export function CanvasElementOverlay() {
529
679
  hoveredBorders: hoverInSelectedFrame.borders,
530
680
  }).segments, projectionZoom)
531
681
  : [];
532
- if (presentationTransitioning)
682
+ if (presentationTransitioning || layoutTransitioning || temporaryAppInteraction)
533
683
  return _jsx("style", { "data-test": "canvas-element-overlay-styles", children: overlayStyles });
534
- 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}`))), 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
684
+ 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 && spacingBadge ? (_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(spacingBadge.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
535
685
  ? projectRect(selectedFrame, toRect(element.getBoundingClientRect()), projectionZoom)
536
686
  : 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" })] }));
537
687
  }
@@ -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, IconPlayerPlay, 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, description, icon, onClick, }) {
20
- return (_jsx(IconButton, { variant: "quiet", size: "large", className: "canvas-toolbar__tool", label: label, title: description ?? 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 (_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, { active: tool === "design", label: "Design", description: "Design (V): click elements to inspect and edit them", icon: _jsx(IconPointer2, { size: "var(--icon-size-large)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), onClick: () => onToolChange("design") }), _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") })] }), _jsx("div", { className: "canvas-toolbar__divider", "aria-hidden": "true" }), _jsx("div", { className: "canvas-toolbar__tools", role: "group", "aria-label": "Preview tools", children: _jsx(ToolButton, { active: tool === "select", label: "Select", description: "Select (I): use the app normally", icon: _jsx(IconPlayerPlay, { size: "var(--icon-size-large)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), onClick: () => onToolChange("select") }) })] }));
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
  }