@agent-native/core 0.42.0 → 0.44.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 (139) hide show
  1. package/README.md +17 -56
  2. package/dist/chat-threads/store.d.ts.map +1 -1
  3. package/dist/chat-threads/store.js +71 -10
  4. package/dist/chat-threads/store.js.map +1 -1
  5. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  6. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  7. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  8. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  9. package/dist/cli/recap.d.ts.map +1 -1
  10. package/dist/cli/recap.js +13 -13
  11. package/dist/cli/recap.js.map +1 -1
  12. package/dist/cli/skills.d.ts +2 -6
  13. package/dist/cli/skills.d.ts.map +1 -1
  14. package/dist/cli/skills.js +21 -79
  15. package/dist/cli/skills.js.map +1 -1
  16. package/dist/client/AssistantChat.d.ts.map +1 -1
  17. package/dist/client/AssistantChat.js +76 -18
  18. package/dist/client/AssistantChat.js.map +1 -1
  19. package/dist/client/blocks/index.d.ts +9 -0
  20. package/dist/client/blocks/index.d.ts.map +1 -1
  21. package/dist/client/blocks/index.js +9 -0
  22. package/dist/client/blocks/index.js.map +1 -1
  23. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  24. package/dist/client/blocks/library/AnnotatedCodeBlock.js +3 -3
  25. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  26. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
  27. package/dist/client/blocks/library/ApiEndpointBlock.js +1 -1
  28. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
  29. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  30. package/dist/client/blocks/library/DiffBlock.js +128 -19
  31. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  32. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
  33. package/dist/client/blocks/library/FileTreeBlock.js +31 -4
  34. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
  35. package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
  36. package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
  37. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  38. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  39. package/dist/client/blocks/library/callout.config.d.ts +29 -0
  40. package/dist/client/blocks/library/callout.config.d.ts.map +1 -0
  41. package/dist/client/blocks/library/callout.config.js +33 -0
  42. package/dist/client/blocks/library/callout.config.js.map +1 -0
  43. package/dist/client/blocks/library/callout.d.ts +20 -0
  44. package/dist/client/blocks/library/callout.d.ts.map +1 -0
  45. package/dist/client/blocks/library/callout.js +61 -0
  46. package/dist/client/blocks/library/callout.js.map +1 -0
  47. package/dist/client/blocks/library/checklist.d.ts.map +1 -1
  48. package/dist/client/blocks/library/checklist.js +3 -3
  49. package/dist/client/blocks/library/checklist.js.map +1 -1
  50. package/dist/client/blocks/library/code-tabs.js +1 -1
  51. package/dist/client/blocks/library/code-tabs.js.map +1 -1
  52. package/dist/client/blocks/library/diagram.config.d.ts +64 -0
  53. package/dist/client/blocks/library/diagram.config.d.ts.map +1 -0
  54. package/dist/client/blocks/library/diagram.config.js +111 -0
  55. package/dist/client/blocks/library/diagram.config.js.map +1 -0
  56. package/dist/client/blocks/library/diagram.d.ts +16 -0
  57. package/dist/client/blocks/library/diagram.d.ts.map +1 -0
  58. package/dist/client/blocks/library/diagram.js +261 -0
  59. package/dist/client/blocks/library/diagram.js.map +1 -0
  60. package/dist/client/blocks/library/question-form.config.d.ts +69 -0
  61. package/dist/client/blocks/library/question-form.config.d.ts.map +1 -0
  62. package/dist/client/blocks/library/question-form.config.js +58 -0
  63. package/dist/client/blocks/library/question-form.config.js.map +1 -0
  64. package/dist/client/blocks/library/question-form.d.ts +20 -0
  65. package/dist/client/blocks/library/question-form.d.ts.map +1 -0
  66. package/dist/client/blocks/library/question-form.js +286 -0
  67. package/dist/client/blocks/library/question-form.js.map +1 -0
  68. package/dist/client/blocks/library/sanitize-html.d.ts +5 -0
  69. package/dist/client/blocks/library/sanitize-html.d.ts.map +1 -0
  70. package/dist/client/blocks/library/sanitize-html.js +240 -0
  71. package/dist/client/blocks/library/sanitize-html.js.map +1 -0
  72. package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
  73. package/dist/client/blocks/library/server-specs.js +49 -0
  74. package/dist/client/blocks/library/server-specs.js.map +1 -1
  75. package/dist/client/blocks/library/specs.d.ts.map +1 -1
  76. package/dist/client/blocks/library/specs.js +9 -0
  77. package/dist/client/blocks/library/specs.js.map +1 -1
  78. package/dist/client/blocks/library/tabs.d.ts.map +1 -1
  79. package/dist/client/blocks/library/tabs.js +12 -12
  80. package/dist/client/blocks/library/tabs.js.map +1 -1
  81. package/dist/client/blocks/library/wireframe-kit.d.ts +260 -0
  82. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -0
  83. package/dist/client/blocks/library/wireframe-kit.js +920 -0
  84. package/dist/client/blocks/library/wireframe-kit.js.map +1 -0
  85. package/dist/client/blocks/library/wireframe.config.d.ts +123 -0
  86. package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -0
  87. package/dist/client/blocks/library/wireframe.config.js +311 -0
  88. package/dist/client/blocks/library/wireframe.config.js.map +1 -0
  89. package/dist/client/blocks/library/wireframe.d.ts +15 -0
  90. package/dist/client/blocks/library/wireframe.d.ts.map +1 -0
  91. package/dist/client/blocks/library/wireframe.js +206 -0
  92. package/dist/client/blocks/library/wireframe.js.map +1 -0
  93. package/dist/client/blocks/mdx.d.ts.map +1 -1
  94. package/dist/client/blocks/mdx.js +11 -0
  95. package/dist/client/blocks/mdx.js.map +1 -1
  96. package/dist/client/blocks/registry.d.ts +9 -0
  97. package/dist/client/blocks/registry.d.ts.map +1 -1
  98. package/dist/client/blocks/registry.js +12 -5
  99. package/dist/client/blocks/registry.js.map +1 -1
  100. package/dist/client/blocks/server.d.ts +1 -0
  101. package/dist/client/blocks/server.d.ts.map +1 -1
  102. package/dist/client/blocks/server.js +1 -0
  103. package/dist/client/blocks/server.js.map +1 -1
  104. package/dist/client/blocks/types.d.ts +8 -0
  105. package/dist/client/blocks/types.d.ts.map +1 -1
  106. package/dist/client/blocks/types.js.map +1 -1
  107. package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
  108. package/dist/client/rich-markdown-editor/DragHandle.js +112 -84
  109. package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
  110. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
  111. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +1 -1
  112. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  113. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +9 -1
  114. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
  115. package/dist/client/rich-markdown-editor/SharedRichEditor.js +3 -1
  116. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
  117. package/dist/client/rich-markdown-editor/extensions.d.ts +13 -1
  118. package/dist/client/rich-markdown-editor/extensions.d.ts.map +1 -1
  119. package/dist/client/rich-markdown-editor/extensions.js +4 -2
  120. package/dist/client/rich-markdown-editor/extensions.js.map +1 -1
  121. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  122. package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -1
  123. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  124. package/dist/server/poll.d.ts.map +1 -1
  125. package/dist/server/poll.js +30 -14
  126. package/dist/server/poll.js.map +1 -1
  127. package/dist/styles/agent-native.css +1 -0
  128. package/dist/styles/blocks.css +1388 -0
  129. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
  130. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
  131. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
  132. package/docs/content/plan-plugin.md +8 -8
  133. package/docs/content/pr-visual-recap.md +2 -2
  134. package/docs/content/template-plan.md +94 -17
  135. package/package.json +2 -1
  136. package/src/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
  137. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
  138. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
  139. package/docs/content/visual-plans.md +0 -82
@@ -12,16 +12,50 @@ import { Plugin, PluginKey, NodeSelection, TextSelection, } from "@tiptap/pm/sta
12
12
  export const DEFAULT_DRAG_HANDLE_WRAPPER_SELECTOR = ".visual-editor-wrapper";
13
13
  const dragHandleKey = new PluginKey("dragHandle");
14
14
  const HOVER_SIDE_OUTSET_REM = 8;
15
- const SIDE_DROP_ZONE_RATIO = 0.28;
16
- const SIDE_DROP_ZONE_MIN_PX = 48;
17
- const SIDE_DROP_ZONE_MAX_PX = 140;
15
+ // Notion-style side drop: drag a block to a neighbour's LEFT/RIGHT region and it
16
+ // builds (or joins) a column layout instead of reordering. The activation region
17
+ // has to be GENEROUS or the gesture is dead for a real human — a natural drag
18
+ // releases somewhere over the block's body, nowhere near a thin edge sliver. The
19
+ // old values (28% of width, capped at 140px, AND only the vertical middle 60%)
20
+ // left a wide ~820px plan block with two ~17%-of-width edge slivers in a 35px-tall
21
+ // band as the ONLY column targets — ~66% of the block (the whole centre) plus the
22
+ // top/bottom only ever reordered, so "drag side by side" essentially never made
23
+ // columns. Now each side claims ~a third of the width across the FULL block
24
+ // height, with a middle band always preserved for before/after reorder.
25
+ const SIDE_DROP_ZONE_RATIO = 0.33;
26
+ const SIDE_DROP_ZONE_MIN_PX = 56;
27
+ const SIDE_DROP_ZONE_MAX_PX = 320;
28
+ // Never let the two side zones swallow the whole block: keep at least the middle
29
+ // ~10% of the width as the before/after reorder band so dropping over the centre
30
+ // still moves the block above/below the target (Notion keeps reorder reachable).
31
+ const SIDE_DROP_ZONE_MAX_WIDTH_FRACTION = 0.45;
18
32
  const DRAG_HANDLE_MENU_STYLE_ID = "an-rich-md-drag-menu-styles";
19
33
  const DRAG_HANDLE_MENU_WIDTH = 220;
20
34
  const DRAG_HANDLE_MENU_GAP = 6;
21
35
  const DRAG_HANDLE_MENU_VIEWPORT_PADDING = 8;
36
+ /**
37
+ * Wraps Tabler outline icon path data in the standard 24×24 stroke SVG so the
38
+ * DOM-based block menu renders the same icons the React UI uses (Tabler is the
39
+ * framework-wide icon set). The editor is plain DOM, not React, so we inline the
40
+ * markup instead of importing `@tabler/icons-react` components.
41
+ */
42
+ const tablerIconSvg = (paths) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${paths}</svg>`;
43
+ // Tabler `copy`, `trash`, and `plus` (outline). Path data copied verbatim from
44
+ // @tabler/icons so the glyphs stay pixel-identical to the React icon set.
45
+ const DRAG_HANDLE_MENU_ICON_DUPLICATE = tablerIconSvg('<path d="M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666" /><path d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1" />');
46
+ const DRAG_HANDLE_MENU_ICON_DELETE = tablerIconSvg('<path d="M4 7l16 0" /><path d="M10 11l0 6" /><path d="M14 11l0 6" /><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" /><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />');
47
+ const DRAG_HANDLE_MENU_ICON_INSERT = tablerIconSvg('<path d="M12 5l0 14" /><path d="M5 12l14 0" />');
48
+ // Tabler `grip-vertical` (outline) for the left-margin drag grip.
49
+ const DRAG_HANDLE_GRIP_ICON = tablerIconSvg('<path d="M8 5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M8 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M8 19a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M14 5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M14 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" /><path d="M14 19a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />');
22
50
  const dragHandleRegistrations = new Set();
23
51
  let dragHandleGlobalHoverListeners = 0;
24
52
  let activeDragRegistration = null;
53
+ // The registration whose grip is currently shown. Used to keep that grip alive
54
+ // while the cursor travels from a block's body to its grip, even when the grip
55
+ // sits in a contested gap (an inter-column gap or a tab body's left offset)
56
+ // where another editor's wide forgiving zone would otherwise re-win the hover
57
+ // and hide the grip out from under the approaching cursor.
58
+ let activeHoverRegistration = null;
25
59
  const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
26
60
  const editorArea = (registration) => {
27
61
  const rect = registration.view.dom.getBoundingClientRect();
@@ -32,6 +66,7 @@ const updateRegisteredHover = (clientX, clientY) => {
32
66
  for (const registration of dragHandleRegistrations) {
33
67
  registration.hideHover?.();
34
68
  }
69
+ activeHoverRegistration = null;
35
70
  return;
36
71
  }
37
72
  const candidates = [];
@@ -48,6 +83,34 @@ const updateRegisteredHover = (clientX, clientY) => {
48
83
  registration.hideHover?.();
49
84
  }
50
85
  }
86
+ // Grip keepalive. Once a block's grip is showing, hold it while the cursor
87
+ // travels LEFT of that block's content toward its grip glyph — within the
88
+ // block's own vertical row and no further left than the glyph itself. This is
89
+ // what makes grips grabbable for blocks that are NOT flush with the page's
90
+ // left gutter (a right column, a tab body): their grip sits in a gap that the
91
+ // neighbour's wide forgiving zone also claims, so the normal picker would flip
92
+ // hover to the neighbour mid-approach and the grip would vanish before the
93
+ // cursor reaches it. The keepalive only bridges the body→grip gap — it does
94
+ // NOT fire while the cursor is over content (so the innermost/nested picking
95
+ // and gutter-grab rules below still decide there) and the row guard stops it
96
+ // from sticking the grip across vertical moves to another block's row.
97
+ if (activeHoverRegistration) {
98
+ const held = candidates.find((candidate) => candidate.registration === activeHoverRegistration);
99
+ const grip = activeHoverRegistration.gripRect?.();
100
+ if (held &&
101
+ grip &&
102
+ clientY >= held.block.rect.top &&
103
+ clientY < held.block.rect.bottom &&
104
+ clientX >= grip.left - 4 &&
105
+ clientX < held.block.rect.left) {
106
+ for (const registration of dragHandleRegistrations) {
107
+ if (registration !== held.registration)
108
+ registration.hideHover?.();
109
+ }
110
+ held.registration.showHoverBlock?.(held.block);
111
+ return;
112
+ }
113
+ }
51
114
  // Pick which editor owns the grip when several register a hover block at this
52
115
  // point. Nested region editors (e.g. each column inside a `columns` block) tile
53
116
  // their container's whole footprint AND extend a wide forgiving zone
@@ -101,6 +164,7 @@ const updateRegisteredHover = (clientX, clientY) => {
101
164
  registration.hideHover?.();
102
165
  }
103
166
  active?.registration.showHoverBlock?.(active.block);
167
+ activeHoverRegistration = active?.registration ?? null;
104
168
  };
105
169
  const handleGlobalHoverMove = (event) => {
106
170
  updateRegisteredHover(event.clientX, event.clientY);
@@ -173,8 +237,10 @@ const ensureDragHandleMenuStyles = () => {
173
237
  }
174
238
 
175
239
  .an-rich-md-drag-menu__icon {
176
- position: relative;
240
+ display: flex;
177
241
  flex: 0 0 auto;
242
+ align-items: center;
243
+ justify-content: center;
178
244
  width: 18px;
179
245
  height: 18px;
180
246
  color: hsl(var(--muted-foreground, 215.4 16.3% 46.9%));
@@ -184,69 +250,9 @@ const ensureDragHandleMenuStyles = () => {
184
250
  color: currentColor;
185
251
  }
186
252
 
187
- .an-rich-md-drag-menu__icon::before,
188
- .an-rich-md-drag-menu__icon::after {
189
- content: "";
190
- position: absolute;
191
- box-sizing: border-box;
192
- }
193
-
194
- .an-rich-md-drag-menu__icon--duplicate::before,
195
- .an-rich-md-drag-menu__icon--duplicate::after {
196
- width: 11px;
197
- height: 11px;
198
- border: 1.5px solid currentColor;
199
- border-radius: 2px;
200
- }
201
-
202
- .an-rich-md-drag-menu__icon--duplicate::before {
203
- left: 6px;
204
- top: 2px;
205
- opacity: 0.55;
206
- }
207
-
208
- .an-rich-md-drag-menu__icon--duplicate::after {
209
- left: 2px;
210
- top: 6px;
211
- background: hsl(var(--popover, 0 0% 100%));
212
- }
213
-
214
- .an-rich-md-drag-menu__icon--insert::before {
215
- left: 3px;
216
- top: 8px;
217
- width: 12px;
218
- height: 1.5px;
219
- border-radius: 999px;
220
- background: currentColor;
221
- }
222
-
223
- .an-rich-md-drag-menu__icon--insert::after {
224
- left: 8px;
225
- top: 3px;
226
- width: 1.5px;
227
- height: 12px;
228
- border-radius: 999px;
229
- background: currentColor;
230
- }
231
-
232
- .an-rich-md-drag-menu__icon--delete::before {
233
- left: 4px;
234
- top: 7px;
235
- width: 10px;
236
- height: 11px;
237
- border: 1.5px solid currentColor;
238
- border-top: 0;
239
- border-radius: 0 0 2px 2px;
240
- }
241
-
242
- .an-rich-md-drag-menu__icon--delete::after {
243
- left: 3px;
244
- top: 4px;
245
- width: 12px;
246
- height: 1.5px;
247
- border-radius: 999px;
248
- background: currentColor;
249
- box-shadow: 3px -2.5px 0 -0.4px currentColor;
253
+ .an-rich-md-drag-menu__icon svg {
254
+ width: 17px;
255
+ height: 17px;
250
256
  }
251
257
 
252
258
  .an-rich-md-drag-menu__label {
@@ -537,7 +543,7 @@ export const DragHandle = Extension.create({
537
543
  DRAG_HANDLE_MENU_VIEWPORT_PADDING)}px`;
538
544
  menu.style.top = `${clamp(anchorRect.top - 4, DRAG_HANDLE_MENU_VIEWPORT_PADDING, viewportHeight - menuHeight - DRAG_HANDLE_MENU_VIEWPORT_PADDING)}px`;
539
545
  };
540
- const createMenuItem = (label, iconModifier, action, options = {}) => {
546
+ const createMenuItem = (label, iconSvg, action, options = {}) => {
541
547
  const button = document.createElement("button");
542
548
  button.type = "button";
543
549
  button.className = "an-rich-md-drag-menu__item";
@@ -546,8 +552,9 @@ export const DragHandle = Extension.create({
546
552
  if (options.danger)
547
553
  button.setAttribute("data-danger", "true");
548
554
  const icon = document.createElement("span");
549
- icon.className = `an-rich-md-drag-menu__icon an-rich-md-drag-menu__icon--${iconModifier}`;
555
+ icon.className = "an-rich-md-drag-menu__icon";
550
556
  icon.setAttribute("aria-hidden", "true");
557
+ icon.innerHTML = iconSvg;
551
558
  const labelElement = document.createElement("span");
552
559
  labelElement.className = "an-rich-md-drag-menu__label";
553
560
  labelElement.textContent = label;
@@ -578,7 +585,9 @@ export const DragHandle = Extension.create({
578
585
  el.setAttribute("role", "menu");
579
586
  el.setAttribute("aria-label", "Block actions");
580
587
  el.setAttribute("data-plan-interactive", "true");
581
- el.append(createMenuItem("Duplicate", "duplicate", duplicateBlock), createMenuItem("Delete", "delete", deleteBlock, { danger: true }), createMenuItem("Insert block below", "insert", insertParagraphBelow));
588
+ el.append(createMenuItem("Duplicate", DRAG_HANDLE_MENU_ICON_DUPLICATE, duplicateBlock), createMenuItem("Delete", DRAG_HANDLE_MENU_ICON_DELETE, deleteBlock, {
589
+ danger: true,
590
+ }), createMenuItem("Insert block below", DRAG_HANDLE_MENU_ICON_INSERT, insertParagraphBelow));
582
591
  menu = el;
583
592
  menuContext = {
584
593
  view: resolved.view,
@@ -613,18 +622,17 @@ export const DragHandle = Extension.create({
613
622
  return null;
614
623
  let placement;
615
624
  const withinBlockY = clientY >= block.rect.top && clientY <= block.rect.bottom;
616
- const withinSideDropBand = clientY >= block.rect.top + block.rect.height * 0.2 &&
617
- clientY <= block.rect.bottom - block.rect.height * 0.2;
618
- const sideZoneWidth = clamp(block.rect.width * SIDE_DROP_ZONE_RATIO, SIDE_DROP_ZONE_MIN_PX, SIDE_DROP_ZONE_MAX_PX);
625
+ // Side (column) zones span the FULL block height only the horizontal
626
+ // position decides column-vs-reorder. Restricting to the vertical middle
627
+ // (the old 0.2 band) made the already-tiny edge slivers nearly unhittable.
628
+ const sideZoneWidth = Math.min(clamp(block.rect.width * SIDE_DROP_ZONE_RATIO, SIDE_DROP_ZONE_MIN_PX, SIDE_DROP_ZONE_MAX_PX), block.rect.width * SIDE_DROP_ZONE_MAX_WIDTH_FRACTION);
619
629
  if (registration.handleDrop &&
620
630
  withinBlockY &&
621
- withinSideDropBand &&
622
631
  clientX <= block.rect.left + sideZoneWidth) {
623
632
  placement = "left";
624
633
  }
625
634
  else if (registration.handleDrop &&
626
635
  withinBlockY &&
627
- withinSideDropBand &&
628
636
  clientX >= block.rect.right - sideZoneWidth) {
629
637
  placement = "right";
630
638
  }
@@ -706,11 +714,21 @@ export const DragHandle = Extension.create({
706
714
  const wrapperRect = wrapper.getBoundingClientRect();
707
715
  const editorRect = target.view.dom.getBoundingClientRect();
708
716
  session.dropTarget = target;
709
- if (target.placement === "left" || target.placement === "right") {
710
- const left = target.placement === "left" ? target.rect.left : target.rect.right;
711
- session.dropLine.style.left = `${left - wrapperRect.left}px`;
717
+ // A column (side) drop and a reorder (before/after) drop both draw the
718
+ // `.notion-drop-indicator`, but they mean very different things, so the
719
+ // column case carries a modifier class apps style distinctly (a bolder,
720
+ // glowing vertical bar) — without a clear cue a human can't tell they've
721
+ // entered column-build mode before releasing.
722
+ const isColumnDrop = target.placement === "left" || target.placement === "right";
723
+ session.dropLine.classList.toggle("notion-drop-indicator--column", isColumnDrop);
724
+ if (isColumnDrop) {
725
+ // A vertical bar centred on the seam at the target's left/right edge,
726
+ // spanning the block's full height.
727
+ const SIDE_BAR_WIDTH = 4;
728
+ const seam = target.placement === "left" ? target.rect.left : target.rect.right;
729
+ session.dropLine.style.left = `${seam - wrapperRect.left - SIDE_BAR_WIDTH / 2}px`;
712
730
  session.dropLine.style.top = `${target.rect.top - wrapperRect.top}px`;
713
- session.dropLine.style.width = "3px";
731
+ session.dropLine.style.width = `${SIDE_BAR_WIDTH}px`;
714
732
  session.dropLine.style.height = `${target.rect.height}px`;
715
733
  return;
716
734
  }
@@ -737,11 +755,15 @@ export const DragHandle = Extension.create({
737
755
  // grip DIV — so a press on the icon gets swallowed and the block can't be
738
756
  // dragged out of / between columns. `pointer-events:none` makes every
739
757
  // press in the grip area resolve to the DIV instead.
740
- el.innerHTML = `<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor" style="pointer-events:none">
741
- <circle cx="5.5" cy="3" r="1.5"/><circle cx="10.5" cy="3" r="1.5"/>
742
- <circle cx="5.5" cy="8" r="1.5"/><circle cx="10.5" cy="8" r="1.5"/>
743
- <circle cx="5.5" cy="13" r="1.5"/><circle cx="10.5" cy="13" r="1.5"/>
744
- </svg>`;
758
+ // Tabler `grip-vertical` (the framework-wide icon set). `pointer-events:none`
759
+ // keeps every press in the grip area resolving to the DIV, not the SVG.
760
+ el.innerHTML = DRAG_HANDLE_GRIP_ICON;
761
+ const gripSvg = el.querySelector("svg");
762
+ if (gripSvg) {
763
+ gripSvg.setAttribute("width", "16");
764
+ gripSvg.setAttribute("height", "16");
765
+ gripSvg.style.pointerEvents = "none";
766
+ }
745
767
  return el;
746
768
  };
747
769
  const hideHandle = () => {
@@ -939,6 +961,9 @@ export const DragHandle = Extension.create({
939
961
  findHoverBlock: (clientX, clientY) => findForgivingBlock(editorView, clientX, clientY),
940
962
  showHoverBlock: (block) => showHandleForBlock(editorView, block),
941
963
  hideHover: () => hideHandle(),
964
+ gripRect: () => handle && handle.style.display !== "none"
965
+ ? handle.getBoundingClientRect()
966
+ : null,
942
967
  };
943
968
  currentRegistration = registration;
944
969
  dragHandleRegistrations.add(registration);
@@ -1010,6 +1035,9 @@ export const DragHandle = Extension.create({
1010
1035
  if (activeDragRegistration === registration) {
1011
1036
  activeDragRegistration = null;
1012
1037
  }
1038
+ if (activeHoverRegistration === registration) {
1039
+ activeHoverRegistration = null;
1040
+ }
1013
1041
  handle?.remove();
1014
1042
  handle = null;
1015
1043
  currentRegistration = null;