@bendyline/squisq-editor-react 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +40 -0
  3. package/README.md +10 -2
  4. package/dist/index.d.ts +683 -60
  5. package/dist/index.js +9648 -3750
  6. package/dist/monaco.js +0 -1
  7. package/dist/styles/index.css +1160 -241
  8. package/package.json +10 -6
  9. package/dist/index.js.map +0 -1
  10. package/dist/monaco.js.map +0 -1
  11. package/src/BlockCardView.tsx +0 -121
  12. package/src/BlockPreviewPanel.tsx +0 -69
  13. package/src/BlockPropertiesPopover.tsx +0 -222
  14. package/src/DocumentSettingsDialog.tsx +0 -272
  15. package/src/DropZoneOverlay.tsx +0 -137
  16. package/src/EditorContext.tsx +0 -1247
  17. package/src/EditorShell.tsx +0 -1334
  18. package/src/EmojiPicker.tsx +0 -332
  19. package/src/FolderView.tsx +0 -131
  20. package/src/Icon.tsx +0 -26
  21. package/src/ImageEditor.tsx +0 -395
  22. package/src/ImageNodeView.tsx +0 -284
  23. package/src/ImageViewer.tsx +0 -221
  24. package/src/InlineIcon.ts +0 -84
  25. package/src/InlinePreviewGutter.tsx +0 -590
  26. package/src/LinkDialog.tsx +0 -276
  27. package/src/MediaBin.tsx +0 -500
  28. package/src/MentionExtension.tsx +0 -261
  29. package/src/OutlinePanel.tsx +0 -547
  30. package/src/PlainHtmlPreview.tsx +0 -277
  31. package/src/PreviewControls.tsx +0 -1250
  32. package/src/PreviewPanel.tsx +0 -422
  33. package/src/RawEditor.tsx +0 -731
  34. package/src/RecorderEntry.tsx +0 -159
  35. package/src/StatusBar.tsx +0 -51
  36. package/src/TemplateAnnotation.ts +0 -167
  37. package/src/TemplateContentPreview.tsx +0 -56
  38. package/src/TemplatePicker.tsx +0 -1314
  39. package/src/ThemeCustomizerPanel.tsx +0 -304
  40. package/src/ThemePicker.tsx +0 -433
  41. package/src/TimelineBlockPreview.tsx +0 -37
  42. package/src/TimelineTrack.tsx +0 -671
  43. package/src/Toolbar.tsx +0 -2587
  44. package/src/Tooltip.tsx +0 -142
  45. package/src/TransitionPicker.tsx +0 -390
  46. package/src/VersionHistoryPanel.tsx +0 -359
  47. package/src/ViewMenuPanel.tsx +0 -189
  48. package/src/ViewSwitcher.tsx +0 -56
  49. package/src/WysiwygEditor.tsx +0 -792
  50. package/src/__tests__/blockProperties.test.ts +0 -92
  51. package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +0 -33
  52. package/src/__tests__/blockRange.test.ts +0 -105
  53. package/src/__tests__/blockTagActivity.test.ts +0 -183
  54. package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +0 -75
  55. package/src/__tests__/buildPreviewDocContent.test.ts +0 -48
  56. package/src/__tests__/buildPreviewDocTransition.test.ts +0 -92
  57. package/src/__tests__/canvasSurfaceTextEditing.test.tsx +0 -60
  58. package/src/__tests__/codeContextSectionView.test.tsx +0 -97
  59. package/src/__tests__/codeContextZoneManager.test.ts +0 -127
  60. package/src/__tests__/createShapeLayer.test.ts +0 -46
  61. package/src/__tests__/customLayoutManagerTheme.test.tsx +0 -34
  62. package/src/__tests__/detectMarkdown.test.ts +0 -73
  63. package/src/__tests__/diffContextSections.test.ts +0 -39
  64. package/src/__tests__/documentSettingsDialog.test.tsx +0 -197
  65. package/src/__tests__/drawingShapeRoundTrip.test.ts +0 -49
  66. package/src/__tests__/editorScrollHandoff.test.tsx +0 -102
  67. package/src/__tests__/editorScrollSync.test.ts +0 -65
  68. package/src/__tests__/editorShellCodeContext.test.tsx +0 -86
  69. package/src/__tests__/editorShellProps.test.tsx +0 -485
  70. package/src/__tests__/embeddedMedia.test.ts +0 -48
  71. package/src/__tests__/emojiPicker.test.tsx +0 -93
  72. package/src/__tests__/fileKind.test.ts +0 -112
  73. package/src/__tests__/headingTransition.test.ts +0 -176
  74. package/src/__tests__/imageEditAffordance.test.tsx +0 -272
  75. package/src/__tests__/imageEditModalContract.test.tsx +0 -119
  76. package/src/__tests__/imageEditorShell.test.tsx +0 -94
  77. package/src/__tests__/imageEditorState.test.ts +0 -171
  78. package/src/__tests__/inlinePreviewGutter.test.tsx +0 -62
  79. package/src/__tests__/inlinePreviewGutterAllBlocks.test.tsx +0 -103
  80. package/src/__tests__/jsonEditor.test.tsx +0 -223
  81. package/src/__tests__/layersPanel.test.tsx +0 -167
  82. package/src/__tests__/layoutChildRoundTrip.test.ts +0 -71
  83. package/src/__tests__/linkDialogDocPicker.test.tsx +0 -137
  84. package/src/__tests__/majorApiTypes.test.ts +0 -26
  85. package/src/__tests__/mediaAttachmentFlow.test.ts +0 -110
  86. package/src/__tests__/mediaBinDrop.test.tsx +0 -90
  87. package/src/__tests__/mediaReferences.test.ts +0 -82
  88. package/src/__tests__/narrationSave.test.ts +0 -148
  89. package/src/__tests__/outlinePanel.test.tsx +0 -169
  90. package/src/__tests__/outlineSource.test.ts +0 -217
  91. package/src/__tests__/plainHtmlPreview.test.tsx +0 -125
  92. package/src/__tests__/presentationMode.test.tsx +0 -290
  93. package/src/__tests__/previewControls.test.tsx +0 -540
  94. package/src/__tests__/previewPanelAudioFailure.test.tsx +0 -46
  95. package/src/__tests__/previewPanelPresentation.test.tsx +0 -126
  96. package/src/__tests__/previewPanelTransforms.test.tsx +0 -117
  97. package/src/__tests__/propertiesPanel.test.tsx +0 -69
  98. package/src/__tests__/rawEditorModelIsolation.test.ts +0 -19
  99. package/src/__tests__/recorderFormats.test.ts +0 -146
  100. package/src/__tests__/recorderMediaInsert.test.ts +0 -86
  101. package/src/__tests__/recorderTheme.test.tsx +0 -42
  102. package/src/__tests__/recorderTimingJson.test.ts +0 -41
  103. package/src/__tests__/resolveBlockVisual.test.ts +0 -43
  104. package/src/__tests__/selectionConversions.test.ts +0 -80
  105. package/src/__tests__/statusBar.test.tsx +0 -27
  106. package/src/__tests__/teleprompter.test.tsx +0 -190
  107. package/src/__tests__/templateAnnotationRoundTrip.test.ts +0 -99
  108. package/src/__tests__/templateContentPreview.test.ts +0 -101
  109. package/src/__tests__/templatePickerMetadata.test.ts +0 -32
  110. package/src/__tests__/templatePickerPortal.test.tsx +0 -62
  111. package/src/__tests__/timelineSource.test.ts +0 -134
  112. package/src/__tests__/tiptapBridge.test.ts +0 -566
  113. package/src/__tests__/tiptapBridgeConformance.test.ts +0 -47
  114. package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +0 -109
  115. package/src/__tests__/tiptapImageRoundTrip.test.ts +0 -73
  116. package/src/__tests__/toolbarSelectionConversion.test.tsx +0 -164
  117. package/src/__tests__/tooltip.test.tsx +0 -72
  118. package/src/__tests__/transformStyleId.test.ts +0 -13
  119. package/src/__tests__/transitionCatalog.test.ts +0 -64
  120. package/src/__tests__/useBlockNavigator.test.tsx +0 -67
  121. package/src/__tests__/useImageEditor.test.tsx +0 -226
  122. package/src/__tests__/useJsonEditorTokens.test.ts +0 -59
  123. package/src/__tests__/useMediaRecorder.test.ts +0 -302
  124. package/src/__tests__/useTimelineClock.test.ts +0 -21
  125. package/src/__tests__/versionHistory.test.tsx +0 -197
  126. package/src/__tests__/viewMenuPanel.test.tsx +0 -130
  127. package/src/__tests__/wysiwygImageUpload.test.ts +0 -69
  128. package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +0 -56
  129. package/src/asciiDiagram/AsciiDiagramExtension.ts +0 -343
  130. package/src/asciiDiagram/AsciiDiagramWidget.tsx +0 -254
  131. package/src/asciiDiagram/RepairableDiagramExtension.ts +0 -200
  132. package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +0 -145
  133. package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +0 -159
  134. package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +0 -284
  135. package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +0 -114
  136. package/src/asciiDiagram/__tests__/asciiPaste.test.ts +0 -43
  137. package/src/asciiDiagram/asciiDiagramCommands.ts +0 -174
  138. package/src/asciiDiagram/asciiDiagramData.ts +0 -149
  139. package/src/asciiDiagram/asciiDiagramOps.ts +0 -238
  140. package/src/asciiDiagram/asciiPaste.ts +0 -19
  141. package/src/blockProperties.ts +0 -88
  142. package/src/blockRange.ts +0 -132
  143. package/src/blockSlice.ts +0 -75
  144. package/src/blockTagActivity.ts +0 -233
  145. package/src/buildDocumentPreviewMarkdown.ts +0 -168
  146. package/src/buildPreviewDoc.ts +0 -405
  147. package/src/codeContext/CodeContextSectionView.tsx +0 -124
  148. package/src/codeContext/CodeContextZoneManager.ts +0 -149
  149. package/src/codeContext/CodeContextZones.tsx +0 -121
  150. package/src/codeContext/diffContextSections.ts +0 -38
  151. package/src/codeContext/types.ts +0 -75
  152. package/src/customTemplates/AddBin.tsx +0 -126
  153. package/src/customTemplates/CustomLayoutManager.tsx +0 -234
  154. package/src/customTemplates/CustomTemplateContext.tsx +0 -188
  155. package/src/customTemplates/LayerToolbar.tsx +0 -580
  156. package/src/customTemplates/ShapeGlyph.tsx +0 -47
  157. package/src/customTemplates/TemplateDesigner.tsx +0 -433
  158. package/src/customTemplates/__tests__/library.test.ts +0 -96
  159. package/src/customTemplates/__tests__/normalizePositions.test.ts +0 -109
  160. package/src/customTemplates/__tests__/shapeDefs.test.ts +0 -49
  161. package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +0 -108
  162. package/src/customTemplates/designer.css +0 -732
  163. package/src/customTemplates/index.ts +0 -31
  164. package/src/customTemplates/library.ts +0 -110
  165. package/src/customTemplates/normalizePositions.ts +0 -75
  166. package/src/customTemplates/shapeDefs.ts +0 -131
  167. package/src/customTemplates/thumbnail.tsx +0 -63
  168. package/src/customTemplates/tokenDefs.ts +0 -60
  169. package/src/customTemplates/useDocCustomTemplates.ts +0 -52
  170. package/src/customTemplates/useMemoryLayerAdapter.ts +0 -129
  171. package/src/customThemes/CustomThemeContext.tsx +0 -185
  172. package/src/customThemes/CustomThemeDialog.tsx +0 -316
  173. package/src/customThemes/ImportThemeSection.tsx +0 -178
  174. package/src/customThemes/__tests__/CustomThemeContext.test.tsx +0 -64
  175. package/src/customThemes/__tests__/CustomThemeDialog.test.tsx +0 -47
  176. package/src/customThemes/__tests__/customThemeLibrary.test.ts +0 -60
  177. package/src/customThemes/__tests__/importThemeSection.test.tsx +0 -192
  178. package/src/customThemes/customThemeLibrary.ts +0 -100
  179. package/src/customThemes/index.ts +0 -37
  180. package/src/customThemes/themeControls.tsx +0 -229
  181. package/src/customThemes/themeDraft.ts +0 -288
  182. package/src/customThemes/useDocCustomThemes.ts +0 -49
  183. package/src/detectMarkdown.ts +0 -62
  184. package/src/diagram/DiagramCanvas.tsx +0 -259
  185. package/src/diagram/DiagramMaximizedOverlay.tsx +0 -46
  186. package/src/diagram/diagramCommands.ts +0 -604
  187. package/src/diagram/diagramConstants.ts +0 -17
  188. package/src/diagram/types.ts +0 -35
  189. package/src/editorScrollSync.ts +0 -73
  190. package/src/embeddedMedia.ts +0 -78
  191. package/src/emojiData.ts +0 -1317
  192. package/src/fileKind.ts +0 -158
  193. package/src/frontmatter.ts +0 -29
  194. package/src/frontmatterSettings.ts +0 -23
  195. package/src/headingTransition.ts +0 -291
  196. package/src/hooks/useFileDrop.ts +0 -266
  197. package/src/imageEditor/CanvasSurface.tsx +0 -703
  198. package/src/imageEditor/ImageVersionHistoryDropdown.tsx +0 -396
  199. package/src/imageEditor/LayersPanel.tsx +0 -218
  200. package/src/imageEditor/PropertiesPanel.tsx +0 -474
  201. package/src/imageEditor/Toolbar.tsx +0 -459
  202. package/src/imageEditor/createShapeLayer.ts +0 -280
  203. package/src/imageEditor/icons.tsx +0 -68
  204. package/src/imageEditor/image-editor.css +0 -574
  205. package/src/imageEditor/layers/EditorImageLayer.tsx +0 -45
  206. package/src/imageEditor/layers/EditorShapeLayer.tsx +0 -62
  207. package/src/imageEditor/layers/EditorTextLayer.tsx +0 -45
  208. package/src/imageEditor/layers/SelectionHandles.tsx +0 -86
  209. package/src/imageEditor/state.ts +0 -173
  210. package/src/imageEditor/useImageEditor.ts +0 -385
  211. package/src/imageEditor/useImageEditorTokens.ts +0 -70
  212. package/src/index.ts +0 -470
  213. package/src/jsonEditor/EmbeddedRichTextField.tsx +0 -81
  214. package/src/jsonEditor/JsonEditor.tsx +0 -81
  215. package/src/jsonEditor/JsonEditorContext.tsx +0 -81
  216. package/src/jsonEditor/RenderNode.tsx +0 -87
  217. package/src/jsonEditor/editors.tsx +0 -745
  218. package/src/jsonEditor/index.ts +0 -2
  219. package/src/jsonEditor/json-editor.css +0 -463
  220. package/src/jsonEditor/useJsonEditorTokens.ts +0 -33
  221. package/src/mediaDragMime.ts +0 -32
  222. package/src/mediaEntries.ts +0 -12
  223. package/src/mediaReferences.ts +0 -299
  224. package/src/monaco.ts +0 -35
  225. package/src/monacoWorkers.ts +0 -89
  226. package/src/outlineSource.ts +0 -171
  227. package/src/presentation/PresentationMode.tsx +0 -596
  228. package/src/rawEditorIsolation.ts +0 -18
  229. package/src/recorder/RecorderButton.tsx +0 -80
  230. package/src/recorder/RecorderModal.tsx +0 -706
  231. package/src/recorder/RecorderPanel.tsx +0 -77
  232. package/src/recorder/formats.ts +0 -159
  233. package/src/recorder/hooks/useMediaRecorder.ts +0 -436
  234. package/src/recorder/hooks/useStreamPreview.ts +0 -47
  235. package/src/recorder/insertMediaBlock.ts +0 -30
  236. package/src/recorder/sources/cameraStream.ts +0 -32
  237. package/src/recorder/sources/micStream.ts +0 -25
  238. package/src/recorder/sources/screenStream.ts +0 -162
  239. package/src/recorder/timingJson.ts +0 -66
  240. package/src/resolveBlockVisual.ts +0 -39
  241. package/src/scene/Scene.tsx +0 -616
  242. package/src/scene/SceneBlockExtension.ts +0 -205
  243. package/src/scene/SceneBlockToolbar.tsx +0 -201
  244. package/src/scene/SceneBlockWidget.tsx +0 -441
  245. package/src/scene/ScenePropsBar.tsx +0 -85
  246. package/src/scene/SceneSelection.tsx +0 -111
  247. package/src/scene/SceneSideToolbar.tsx +0 -89
  248. package/src/scene/SceneViewport.tsx +0 -106
  249. package/src/scene/ShapePalette.tsx +0 -196
  250. package/src/scene/__tests__/DiagramAdapter.test.ts +0 -142
  251. package/src/scene/__tests__/SceneBlockExtension.test.ts +0 -33
  252. package/src/scene/__tests__/bezierEdit.test.ts +0 -85
  253. package/src/scene/__tests__/blockLayers.test.ts +0 -57
  254. package/src/scene/__tests__/sceneIsolation.test.tsx +0 -119
  255. package/src/scene/__tests__/shapeLayers.test.ts +0 -106
  256. package/src/scene/__tests__/useSceneHitTest.test.ts +0 -90
  257. package/src/scene/__tests__/useScenePanZoom.test.ts +0 -103
  258. package/src/scene/adapters/DiagramAdapter.ts +0 -79
  259. package/src/scene/adapters/DrawingAdapter.ts +0 -420
  260. package/src/scene/adapters/LayoutAdapter.ts +0 -313
  261. package/src/scene/adapters/blockLayers.ts +0 -159
  262. package/src/scene/commands/SceneCommand.ts +0 -84
  263. package/src/scene/commands/drawingCommands.ts +0 -318
  264. package/src/scene/commands/layoutCommands.ts +0 -301
  265. package/src/scene/hooks/useSceneHitTest.ts +0 -105
  266. package/src/scene/hooks/useScenePanZoom.ts +0 -147
  267. package/src/scene/hooks/useSceneSelection.ts +0 -62
  268. package/src/scene/index.ts +0 -90
  269. package/src/scene/layers/DiagramEdges.tsx +0 -142
  270. package/src/scene/layers/edgeGeometry.ts +0 -104
  271. package/src/scene/layers/nodeCard.tsx +0 -164
  272. package/src/scene/layers/renderLayer.tsx +0 -70
  273. package/src/scene/layers/shapeLayers.ts +0 -201
  274. package/src/scene/paths/bezierEdit.ts +0 -208
  275. package/src/scene/scene.css +0 -792
  276. package/src/scene/text/SceneTextOverlay.tsx +0 -161
  277. package/src/scene/text/sceneTextChannel.ts +0 -46
  278. package/src/scene/text/sceneTextConfig.ts +0 -31
  279. package/src/scene/text/sceneTiptap.ts +0 -36
  280. package/src/scene/text/useSceneTextEditing.ts +0 -39
  281. package/src/scene/tools/ConnectTool.ts +0 -209
  282. package/src/scene/tools/DrawingConnectTool.ts +0 -231
  283. package/src/scene/tools/PathTool.ts +0 -158
  284. package/src/scene/tools/PlaceTool.ts +0 -47
  285. package/src/scene/tools/SceneTool.ts +0 -85
  286. package/src/scene/tools/SelectTool.ts +0 -300
  287. package/src/scene/tools/ShapeTool.ts +0 -143
  288. package/src/scene/tools/TextTool.ts +0 -72
  289. package/src/scene/tools/TokenTool.ts +0 -95
  290. package/src/scene/tools/createDrawShapeTool.ts +0 -82
  291. package/src/selectionConversions.ts +0 -155
  292. package/src/styles/ascii-diagram.css +0 -79
  293. package/src/styles/ascii-timeline.css +0 -596
  294. package/src/styles/code-context.css +0 -155
  295. package/src/styles/diagram.css +0 -183
  296. package/src/styles/editor.css +0 -6811
  297. package/src/styles/folder-view.css +0 -210
  298. package/src/styles/image-edit-affordance.css +0 -201
  299. package/src/styles/index.css +0 -18
  300. package/src/styles/tree-view.css +0 -189
  301. package/src/teleprompter/TeleprompterControls.tsx +0 -218
  302. package/src/teleprompter/TeleprompterSelfView.tsx +0 -22
  303. package/src/teleprompter/TeleprompterSurface.tsx +0 -267
  304. package/src/teleprompter/TeleprompterView.tsx +0 -338
  305. package/src/teleprompter/canvasRenderer.ts +0 -161
  306. package/src/teleprompter/floatingWindow.ts +0 -352
  307. package/src/teleprompter/index.ts +0 -61
  308. package/src/teleprompter/pcmWorklet.ts +0 -62
  309. package/src/teleprompter/recording/insertPreamble.ts +0 -80
  310. package/src/teleprompter/recording/narrationSave.ts +0 -134
  311. package/src/teleprompter/recording/useNarrationRecorder.ts +0 -367
  312. package/src/teleprompter/scrollModel.ts +0 -85
  313. package/src/teleprompter/teleprompterTheme.ts +0 -303
  314. package/src/teleprompter/types.ts +0 -38
  315. package/src/teleprompter/useFloatingWindow.ts +0 -74
  316. package/src/teleprompter/useMicAnalysis.ts +0 -211
  317. package/src/teleprompter/useTeleprompter.ts +0 -421
  318. package/src/templateContentPreviewResolver.ts +0 -360
  319. package/src/timeline/TimelineEditorWidget.tsx +0 -861
  320. package/src/timeline/TimelineViewExtension.ts +0 -252
  321. package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +0 -414
  322. package/src/timeline/__tests__/TimelineViewExtension.test.ts +0 -163
  323. package/src/timeline/__tests__/timelineCommands.test.ts +0 -359
  324. package/src/timeline/__tests__/timelineOps.test.ts +0 -277
  325. package/src/timeline/__tests__/timelinePaste.test.ts +0 -34
  326. package/src/timeline/timelineCommands.ts +0 -421
  327. package/src/timeline/timelineData.ts +0 -54
  328. package/src/timeline/timelineOps.ts +0 -381
  329. package/src/timeline/timelinePaste.ts +0 -8
  330. package/src/timelineSource.ts +0 -244
  331. package/src/tiptap/TiptapAudio.tsx +0 -86
  332. package/src/tiptap/TiptapVideo.tsx +0 -119
  333. package/src/tiptap/useResolvedMediaSrc.ts +0 -47
  334. package/src/tiptapBridge.ts +0 -986
  335. package/src/tooltipPlacement.ts +0 -13
  336. package/src/transformStyleId.ts +0 -17
  337. package/src/transitionCatalog.ts +0 -159
  338. package/src/treeview/TreeOutlineWidget.tsx +0 -390
  339. package/src/treeview/TreeViewExtension.ts +0 -250
  340. package/src/treeview/__tests__/TreeOutlineWidget.test.tsx +0 -156
  341. package/src/treeview/__tests__/TreeViewExtension.test.ts +0 -122
  342. package/src/treeview/__tests__/treeOps.test.ts +0 -177
  343. package/src/treeview/__tests__/treePaste.test.ts +0 -40
  344. package/src/treeview/__tests__/treeViewCommands.test.ts +0 -179
  345. package/src/treeview/treeOps.ts +0 -231
  346. package/src/treeview/treePaste.ts +0 -13
  347. package/src/treeview/treeViewCommands.ts +0 -99
  348. package/src/treeview/treeViewData.ts +0 -41
  349. package/src/types/monaco-shims.d.ts +0 -10
  350. package/src/useBlockNavigator.ts +0 -153
  351. package/src/useHeadingLayout.ts +0 -294
  352. package/src/useMonacoLoader.ts +0 -82
  353. package/src/useTimelineClock.ts +0 -76
  354. package/src/utils/collectInlineFontAwesomeCss.ts +0 -69
  355. package/src/utils/dropUtils.ts +0 -136
  356. package/src/utils/normalizeMalformedAssetUrl.ts +0 -22
  357. package/src/wysiwygImageUpload.ts +0 -113
@@ -1,441 +0,0 @@
1
- /**
2
- * SceneBlockWidget — Squisq-Scene-backed canvas mounted under a
3
- * heading whose `dataTemplate` is `layout` or `drawing`.
4
- *
5
- * Owns the maximize toggle and picks the right adapter for the mode.
6
- * Resolves the heading's position dynamically each render via
7
- * `headingKey`, so the widget survives attribute-only doc changes
8
- * without going stale when content above shifts.
9
- *
10
- * In `drawing` mode it also hosts the shape palette (gallery of shape
11
- * kinds) and the properties panel for the current selection — surfaced
12
- * from the drawing adapter + the Scene's `onSelectionChange`.
13
- */
14
-
15
- import { useEffect, useMemo, useRef, useState } from 'react';
16
- import type { ReactNode } from 'react';
17
- import type { Editor } from '@tiptap/react';
18
- import type { Layer } from '@bendyline/squisq/schemas';
19
- import { Scene } from './Scene';
20
- import { useLayoutAdapter } from './adapters/LayoutAdapter';
21
- import { useDrawingAdapter, type ConnectorStyleInput } from './adapters/DrawingAdapter';
22
- import type { SceneCommand, SceneEdge } from './commands/SceneCommand';
23
- import { findSceneHeadingPos } from './SceneBlockExtension';
24
- import { shapeIdFromLayerId } from './layers/shapeLayers';
25
- import { ShapePalette } from './ShapePalette';
26
- import { ScenePropsBar } from './ScenePropsBar';
27
- import { SceneBlockToolbar, type SceneBlockAction, type SceneAlignment } from './SceneBlockToolbar';
28
- import { SceneSideToolbar } from './SceneSideToolbar';
29
- import type { SceneTextEditConfig } from './text/sceneTextConfig';
30
- import { markdownToTiptap } from '../tiptapBridge';
31
- import { Icon } from '../Icon';
32
- import { DiagramMaximizedOverlay } from '../diagram/DiagramMaximizedOverlay';
33
- import type { SceneTextChannel } from './text/sceneTextChannel';
34
-
35
- export type SceneBlockMode = 'layout' | 'drawing';
36
-
37
- interface SceneBlockWidgetProps {
38
- editor: Editor;
39
- headingKey: string;
40
- fallbackParentPos: number;
41
- mode: SceneBlockMode;
42
- /** Host element for portal targeting (used by maximize overlay). */
43
- host?: HTMLElement | null;
44
- textChannel?: SceneTextChannel;
45
- }
46
-
47
- // Default viewport for layout/drawing surfaces. Matches Squisq's 16:9
48
- // preview so layouts authored here render correctly when previewed.
49
- const SCENE_VIEWPORT = { width: 1920, height: 1080 };
50
-
51
- // Connector style vocabularies for the inline properties (drawing edges).
52
- const MARKERS = ['none', 'arrow', 'open', 'diamond', 'circle', 'square'];
53
- const ROUTINGS = ['straight', 'orthogonal', 'curved'];
54
- const LINE_STYLES = ['solid', 'dashed', 'dotted'];
55
- const lineStyleOf = (dasharray: string | undefined): string =>
56
- dasharray === '8 6' ? 'dashed' : dasharray === '2 6' ? 'dotted' : 'solid';
57
-
58
- export function SceneBlockWidget({
59
- editor,
60
- headingKey,
61
- fallbackParentPos,
62
- mode,
63
- host,
64
- textChannel,
65
- }: SceneBlockWidgetProps) {
66
- const [parentPos, setParentPos] = useState<number>(
67
- () => findSceneHeadingPos(editor, headingKey, mode) ?? fallbackParentPos,
68
- );
69
- useEffect(() => {
70
- const onUpdate = () => {
71
- const next = findSceneHeadingPos(editor, headingKey, mode);
72
- if (next != null && next !== parentPos) setParentPos(next);
73
- };
74
- editor.on('transaction', onUpdate);
75
- return () => {
76
- editor.off('transaction', onUpdate);
77
- };
78
- }, [editor, headingKey, mode, parentPos]);
79
-
80
- const layout = useLayoutAdapter(editor, parentPos);
81
- const drawing = useDrawingAdapter(editor, parentPos);
82
- const isDrawing = mode === 'drawing';
83
- const adapter = isDrawing ? drawing : layout;
84
-
85
- // Inline text editing config. Refs keep `getHtml`/`commit` reading the
86
- // live layers/dispatch while the config object stays stable (so the
87
- // open editor isn't re-seeded mid-edit). Layout stores rich HTML; drawing
88
- // stores inline markdown in the shape's heading text.
89
- const layersRef = useRef(adapter.layers);
90
- layersRef.current = adapter.layers;
91
- const dispatchRef = useRef(adapter.dispatch);
92
- dispatchRef.current = adapter.dispatch;
93
- const textConfig = useMemo<SceneTextEditConfig>(
94
- () => ({
95
- channel: textChannel,
96
- resolveEditableId: (id) => {
97
- const l = layersRef.current.find((x) => x.id === id);
98
- return l && l.type === 'text' ? id : null;
99
- },
100
- getHtml: (id) => {
101
- const l = layersRef.current.find((x) => x.id === id);
102
- if (!l || l.type !== 'text') return '';
103
- if (!isDrawing && l.content.html?.trim()) return l.content.html;
104
- return markdownToTiptap(l.content.text ?? '');
105
- },
106
- commit: (id, { html, text }) => {
107
- if (isDrawing) {
108
- // Drawing labels persist as plain heading text for now (rich
109
- // marks on shape labels are a follow-up — the rendering
110
- // foundation is in place via `content.html`). Store plain text so
111
- // nothing leaks literal markdown into the label.
112
- dispatchRef.current({ kind: 'renameLayer', id, label: text });
113
- } else {
114
- dispatchRef.current({ kind: 'setLayerText', id, text, html });
115
- }
116
- },
117
- // Layout textboxes use `block` (marks + lists, no headings) because their
118
- // content is stored as the child sub-block's markdown body.
119
- level: isDrawing ? 'inline' : 'block',
120
- }),
121
- [isDrawing, textChannel],
122
- );
123
-
124
- const [maximized, setMaximized] = useState(false);
125
- const [activeToolId, setActiveToolId] = useState<string>('select');
126
- const [paletteOpen, setPaletteOpen] = useState(false);
127
- const [selectedLayerId, setSelectedLayerId] = useState<string | null>(null);
128
-
129
- const selectedShapeId = isDrawing && selectedLayerId ? shapeIdFromLayerId(selectedLayerId) : null;
130
-
131
- const canvas = (
132
- <Scene
133
- viewport={SCENE_VIEWPORT}
134
- layers={adapter.layers}
135
- edges={adapter.edges}
136
- tools={adapter.tools}
137
- onCommand={adapter.dispatch}
138
- onSelectionChange={(ids) => setSelectedLayerId(ids.values().next().value ?? null)}
139
- activeToolId={activeToolId}
140
- onActiveToolIdChange={setActiveToolId}
141
- layerFollows={adapter.layerFollows}
142
- renderExtras={adapter.renderExtras}
143
- showMaximize
144
- maximized={maximized}
145
- onToggleMaximize={() => setMaximized((m) => !m)}
146
- showToolbar={false}
147
- textEditing={textConfig}
148
- />
149
- );
150
-
151
- // ── Shared toolbar (above the canvas) ──────────────────
152
- // Drawing creates shapes via its mode tools (Shape/Pen/Text/Connect);
153
- // layout has only Select, so it gets explicit Add buttons. Both share
154
- // a Delete action keyed off the current selection.
155
- const canDelete = isDrawing ? !!selectedLayerId || !!drawing.selectedEdgeId : !!selectedLayerId;
156
- const deleteSelected = () => {
157
- if (selectedLayerId) {
158
- adapter.dispatch({ kind: 'removeLayer', id: selectedLayerId });
159
- setSelectedLayerId(null);
160
- return;
161
- }
162
- if (isDrawing && drawing.selectedEdge) {
163
- adapter.dispatch({
164
- kind: 'removeEdge',
165
- source: drawing.selectedEdge.source,
166
- target: drawing.selectedEdge.target,
167
- });
168
- }
169
- };
170
- const freshLayerId = (prefix: string) => {
171
- const used = new Set(adapter.layers.map((l) => l.id));
172
- let i = 1;
173
- while (used.has(`${prefix}-${i}`)) i++;
174
- return `${prefix}-${i}`;
175
- };
176
- const addLayoutLayer = (layer: Layer) => adapter.dispatch({ kind: 'addLayer', layer });
177
-
178
- const deleteAction: SceneBlockAction = {
179
- id: 'delete',
180
- label: 'Delete',
181
- icon: <Icon icon="fa-solid fa-trash" />,
182
- title: 'Delete selected',
183
- danger: true,
184
- disabled: !canDelete,
185
- onClick: deleteSelected,
186
- };
187
- const actions: SceneBlockAction[] = isDrawing
188
- ? [deleteAction]
189
- : [
190
- {
191
- id: 'add-text',
192
- label: 'Text',
193
- icon: <Icon icon="fa-solid fa-font" />,
194
- title: 'Add text',
195
- onClick: () =>
196
- addLayoutLayer({
197
- type: 'text',
198
- id: freshLayerId('text'),
199
- content: {
200
- text: 'Text',
201
- style: {
202
- fontSize: 48,
203
- color: '#1e293b',
204
- textAlign: 'center',
205
- verticalAlign: 'middle',
206
- },
207
- },
208
- position: { x: 660, y: 440, width: 600, height: 200 },
209
- }),
210
- },
211
- {
212
- id: 'add-box',
213
- label: 'Box',
214
- icon: <Icon icon="fa-solid fa-square" />,
215
- title: 'Add box',
216
- onClick: () =>
217
- addLayoutLayer({
218
- type: 'shape',
219
- id: freshLayerId('box'),
220
- content: {
221
- shape: 'rect',
222
- fill: '#e0e7ff',
223
- stroke: '#6366f1',
224
- strokeWidth: 2,
225
- borderRadius: 8,
226
- },
227
- position: { x: 760, y: 390, width: 400, height: 300 },
228
- }),
229
- },
230
- deleteAction,
231
- ];
232
-
233
- // Text-alignment controls — shown when a layout textbox is selected. They
234
- // set the layer's whole-box `style.textAlign` / `style.verticalAlign`
235
- // (the LayoutAdapter persists arbitrary `content.*` paths; drawing/diagram
236
- // labels don't yet, so this is layout-only for now).
237
- const selectedLayer = selectedLayerId
238
- ? adapter.layers.find((l) => l.id === selectedLayerId)
239
- : undefined;
240
- const alignment: SceneAlignment | undefined =
241
- mode === 'layout' && selectedLayer?.type === 'text'
242
- ? {
243
- textAlign: selectedLayer.content.style.textAlign ?? 'left',
244
- verticalAlign: selectedLayer.content.style.verticalAlign ?? 'top',
245
- onTextAlign: (v) =>
246
- adapter.dispatch({
247
- kind: 'setLayerAttr',
248
- id: selectedLayer.id,
249
- path: 'content.style.textAlign',
250
- value: v,
251
- }),
252
- onVerticalAlign: (v) =>
253
- adapter.dispatch({
254
- kind: 'setLayerAttr',
255
- id: selectedLayer.id,
256
- path: 'content.style.verticalAlign',
257
- value: v,
258
- }),
259
- }
260
- : undefined;
261
-
262
- // Per-selection style controls, rendered inline in the contextual toolbar
263
- // (Fill/Stroke for shapes & boxes, Color for text, marker/line/routing for
264
- // a drawing connector). Replaces the old floating properties panel.
265
- const propsBar = buildPropsBar({
266
- isDrawing,
267
- selectedLayer,
268
- selectedShapeId,
269
- selectedEdge: isDrawing ? drawing.selectedEdge : null,
270
- setShapeParam: drawing.setShapeParam,
271
- setConnectorStyle: drawing.setConnectorStyle,
272
- dispatch: adapter.dispatch,
273
- });
274
-
275
- const toolbar = (
276
- <SceneBlockToolbar
277
- tools={adapter.tools}
278
- activeToolId={activeToolId}
279
- // Clicking the Shape tool opens its palette (dropping down from the
280
- // button); other tools just activate.
281
- onSelectTool={(id) => {
282
- setActiveToolId(id);
283
- if (id === 'draw') setPaletteOpen(true);
284
- }}
285
- actions={actions}
286
- alignment={alignment}
287
- properties={propsBar}
288
- toolPopover={
289
- isDrawing && paletteOpen
290
- ? {
291
- toolId: 'draw',
292
- content: (
293
- <ShapePalette
294
- onPick={(kind) => {
295
- drawing.setPendingKind(kind);
296
- setActiveToolId('draw');
297
- setPaletteOpen(false);
298
- }}
299
- onClose={() => setPaletteOpen(false)}
300
- />
301
- ),
302
- }
303
- : undefined
304
- }
305
- />
306
- );
307
-
308
- const body = <div className="squisq-scene-stage">{canvas}</div>;
309
-
310
- if (maximized) {
311
- return (
312
- <div className="squisq-scene-inline-placeholder">
313
- <DiagramMaximizedOverlay host={host ?? null} onClose={() => setMaximized(false)}>
314
- {/* Maximized has a full screen for a static right column — no collapse. */}
315
- <div className="squisq-scene-block-max">
316
- {body}
317
- <div className="squisq-scene-side-toolbar">{toolbar}</div>
318
- </div>
319
- </DiagramMaximizedOverlay>
320
- </div>
321
- );
322
- }
323
-
324
- return (
325
- <div className="squisq-scene-shell">
326
- {/* Before the canvas so the narrow-width fallback bar sits above it; the
327
- wide-width gutter column is absolute and unaffected by DOM order. */}
328
- <SceneSideToolbar>{toolbar}</SceneSideToolbar>
329
- <div className="squisq-scene-inline">{body}</div>
330
- </div>
331
- );
332
- }
333
-
334
- /**
335
- * Build the inline per-selection style controls for the contextual toolbar.
336
- * - A drawing connector → marker / line / routing dropdowns.
337
- * - A text layer → a single Color swatch (drawing text color is the shape's
338
- * `stroke`; layout text color is `content.style.color`).
339
- * - A shape / box / path → Fill + Stroke swatches.
340
- * Returns null when the selection has nothing styleable.
341
- */
342
- function buildPropsBar(args: {
343
- isDrawing: boolean;
344
- selectedLayer: Layer | undefined;
345
- selectedShapeId: string | null;
346
- selectedEdge: SceneEdge | null;
347
- setShapeParam: (id: string, key: string, value: string) => void;
348
- setConnectorStyle: (id: string, style: ConnectorStyleInput) => void;
349
- dispatch: (cmd: SceneCommand) => void;
350
- }): ReactNode {
351
- const {
352
- isDrawing,
353
- selectedLayer,
354
- selectedShapeId,
355
- selectedEdge,
356
- setShapeParam,
357
- setConnectorStyle,
358
- dispatch,
359
- } = args;
360
-
361
- if (isDrawing && selectedEdge) {
362
- const e = selectedEdge;
363
- const set = (style: ConnectorStyleInput) => setConnectorStyle(e.id, style);
364
- return (
365
- <ScenePropsBar
366
- selects={[
367
- {
368
- label: 'End',
369
- value: e.endMarker ?? 'arrow',
370
- options: MARKERS,
371
- onChange: (v) => set({ endStyle: v }),
372
- },
373
- {
374
- label: 'Start',
375
- value: e.startMarker ?? 'none',
376
- options: MARKERS,
377
- onChange: (v) => set({ startStyle: v }),
378
- },
379
- {
380
- label: 'Line',
381
- value: lineStyleOf(e.dasharray),
382
- options: LINE_STYLES,
383
- onChange: (v) => set({ lineStyle: v }),
384
- },
385
- {
386
- label: 'Routing',
387
- value: e.routing ?? 'straight',
388
- options: ROUTINGS,
389
- onChange: (v) => set({ routing: v }),
390
- },
391
- ]}
392
- />
393
- );
394
- }
395
-
396
- if (!selectedLayer) return null;
397
-
398
- // Drawing maps a shape's params via its heading id; layout writes layer
399
- // attribute paths through the adapter's dispatch.
400
- const setColor = (param: string, path: string) => (v: string) => {
401
- if (isDrawing && selectedShapeId) setShapeParam(selectedShapeId, param, v);
402
- else dispatch({ kind: 'setLayerAttr', id: selectedLayer.id, path, value: v });
403
- };
404
-
405
- if (selectedLayer.type === 'text') {
406
- // Drawing stores a text shape's color in its `stroke` param.
407
- return (
408
- <ScenePropsBar
409
- colors={[
410
- {
411
- label: 'Color',
412
- value: selectedLayer.content.style.color,
413
- onChange: setColor('stroke', 'content.style.color'),
414
- },
415
- ]}
416
- />
417
- );
418
- }
419
-
420
- if (selectedLayer.type === 'shape' || selectedLayer.type === 'path') {
421
- return (
422
- <ScenePropsBar
423
- colors={[
424
- {
425
- label: 'Fill',
426
- value: selectedLayer.content.fill,
427
- allowNone: true,
428
- onChange: setColor('fill', 'content.fill'),
429
- },
430
- {
431
- label: 'Stroke',
432
- value: selectedLayer.content.stroke,
433
- onChange: setColor('stroke', 'content.stroke'),
434
- },
435
- ]}
436
- />
437
- );
438
- }
439
-
440
- return null;
441
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * ScenePropsBar — compact, inline per-selection style controls that live
3
- * INSIDE the contextual toolbar (next to the tool / create buttons), rather
4
- * than in a separate floating panel.
5
- *
6
- * It's intentionally generic: the host (SceneBlockWidget / DiagramWidget)
7
- * decides what the current selection exposes — color swatches (Fill / Stroke
8
- * / text Color) and/or dropdowns (a connector's markers, line style, routing)
9
- * — and passes them as plain `colors` / `selects` descriptors. Renders
10
- * nothing when the selection has no styleable props.
11
- */
12
-
13
- interface ScenePropColor {
14
- label: string;
15
- /** Current color (`#rrggbb`); shown in the swatch. */
16
- value?: string;
17
- /** Show a "none" button that clears the color (emits `'none'`). */
18
- allowNone?: boolean;
19
- onChange: (value: string) => void;
20
- }
21
-
22
- interface ScenePropSelect {
23
- label: string;
24
- value: string;
25
- options: readonly string[];
26
- onChange: (value: string) => void;
27
- }
28
-
29
- export interface ScenePropsBarProps {
30
- colors?: readonly ScenePropColor[];
31
- selects?: readonly ScenePropSelect[];
32
- }
33
-
34
- export function ScenePropsBar({ colors = [], selects = [] }: ScenePropsBarProps) {
35
- if (colors.length === 0 && selects.length === 0) return null;
36
- return (
37
- <div className="squisq-scene-block-props" role="group" aria-label="Selection style">
38
- {colors.map((c) => (
39
- <span className="squisq-scene-prop" key={c.label}>
40
- <span className="squisq-scene-prop-label">{c.label}</span>
41
- <input
42
- type="color"
43
- className="squisq-scene-prop-color"
44
- aria-label={`${c.label} color`}
45
- value={toHexInput(c.value)}
46
- onChange={(e) => c.onChange(e.target.value)}
47
- />
48
- {c.allowNone && (
49
- <button
50
- type="button"
51
- className="squisq-scene-prop-clear"
52
- onClick={() => c.onChange('none')}
53
- >
54
- none
55
- </button>
56
- )}
57
- </span>
58
- ))}
59
- {selects.map((s) => (
60
- <label className="squisq-scene-prop" key={s.label}>
61
- <span className="squisq-scene-prop-label">{s.label}</span>
62
- <select
63
- className="squisq-scene-prop-select"
64
- value={s.value}
65
- onChange={(e) => s.onChange(e.target.value)}
66
- >
67
- {s.options.map((o) => (
68
- <option key={o} value={o}>
69
- {o}
70
- </option>
71
- ))}
72
- </select>
73
- </label>
74
- ))}
75
- </div>
76
- );
77
- }
78
-
79
- /** Coerce an arbitrary color (or `none`/undefined) to a `#rrggbb` the native
80
- * color input can display. Non-hex values fall back to black. */
81
- function toHexInput(value: string | undefined): string {
82
- return value && /^#[0-9a-fA-F]{6}$/.test(value) ? value : '#000000';
83
- }
84
-
85
- export default ScenePropsBar;
@@ -1,111 +0,0 @@
1
- /**
2
- * SceneSelection — selection outline + corner handles for resize.
3
- *
4
- * Renders a dashed bounding box per selected layer plus eight grip
5
- * handles (four corners + four edges). The Scene wires the handles to
6
- * SelectTool's `beginHandleDrag` so a pointer-down on a handle starts a
7
- * resize gesture instead of a move.
8
- *
9
- * All coordinates are viewport units — the parent group transform
10
- * carries pan/zoom. Handle dimensions and stroke widths use
11
- * `vector-effect: non-scaling-stroke` (set in scene.css) so they stay
12
- * the same pixel size regardless of zoom.
13
- */
14
-
15
- import type { HitTestable } from './hooks/useSceneHitTest';
16
-
17
- export type ResizeCorner = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
18
-
19
- interface SceneSelectionProps {
20
- selection: ReadonlySet<string>;
21
- hitItems: readonly HitTestable[];
22
- /** Live offset during a move-drag (applied to outline + handles). */
23
- liveOffset?: { dx: number; dy: number } | null;
24
- /** Live resize bounds, applied to the matching layer's outline. */
25
- liveResize?: {
26
- layerId: string;
27
- bounds: { x: number; y: number; width: number; height: number };
28
- } | null;
29
- /** Fired when the user presses a corner/edge handle. */
30
- onHandlePointerDown?: (e: React.PointerEvent<SVGElement>, corner: ResizeCorner) => void;
31
- /** Whether to render resize handles in addition to the selection outline. */
32
- showHandles?: boolean;
33
- }
34
-
35
- const HANDLE_SIZE = 8;
36
-
37
- export function SceneSelection({
38
- selection,
39
- hitItems,
40
- liveOffset,
41
- liveResize,
42
- onHandlePointerDown,
43
- showHandles = true,
44
- }: SceneSelectionProps) {
45
- if (selection.size === 0) return null;
46
- const selected = hitItems.filter((it) => selection.has(it.id));
47
- if (selected.length === 0) return null;
48
- const offset = liveOffset ?? { dx: 0, dy: 0 };
49
-
50
- return (
51
- <g className="squisq-scene-selection-group">
52
- {selected.map((it) => {
53
- // Prefer the live-resize bounds for the matching layer; otherwise
54
- // apply the move offset.
55
- let x: number;
56
- let y: number;
57
- let w: number;
58
- let h: number;
59
- if (liveResize && liveResize.layerId === it.id) {
60
- x = liveResize.bounds.x;
61
- y = liveResize.bounds.y;
62
- w = liveResize.bounds.width;
63
- h = liveResize.bounds.height;
64
- } else {
65
- x = it.bounds.x + offset.dx;
66
- y = it.bounds.y + offset.dy;
67
- w = it.bounds.width;
68
- h = it.bounds.height;
69
- }
70
- const corners: { corner: ResizeCorner; cx: number; cy: number; cursor: string }[] = [
71
- { corner: 'nw', cx: x, cy: y, cursor: 'nwse-resize' },
72
- { corner: 'n', cx: x + w / 2, cy: y, cursor: 'ns-resize' },
73
- { corner: 'ne', cx: x + w, cy: y, cursor: 'nesw-resize' },
74
- { corner: 'e', cx: x + w, cy: y + h / 2, cursor: 'ew-resize' },
75
- { corner: 'se', cx: x + w, cy: y + h, cursor: 'nwse-resize' },
76
- { corner: 's', cx: x + w / 2, cy: y + h, cursor: 'ns-resize' },
77
- { corner: 'sw', cx: x, cy: y + h, cursor: 'nesw-resize' },
78
- { corner: 'w', cx: x, cy: y + h / 2, cursor: 'ew-resize' },
79
- ];
80
- return (
81
- <g key={it.id} className="squisq-scene-selection">
82
- <rect
83
- x={x}
84
- y={y}
85
- width={w}
86
- height={h}
87
- className="squisq-scene-selection-outline"
88
- pointerEvents="none"
89
- />
90
- {showHandles &&
91
- corners.map(({ corner, cx, cy, cursor }) => (
92
- <rect
93
- key={corner}
94
- x={cx - HANDLE_SIZE / 2}
95
- y={cy - HANDLE_SIZE / 2}
96
- width={HANDLE_SIZE}
97
- height={HANDLE_SIZE}
98
- className="squisq-scene-selection-handle"
99
- style={{ cursor }}
100
- onPointerDown={
101
- onHandlePointerDown ? (e) => onHandlePointerDown(e, corner) : undefined
102
- }
103
- data-corner={corner}
104
- />
105
- ))}
106
- </g>
107
- );
108
- })}
109
- </g>
110
- );
111
- }