@tiptap/extension-drag-handle 3.22.4 → 3.23.1
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.
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +341 -57
- package/dist/index.d.ts +341 -57
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/drag-handle.ts +19 -15
- package/src/types/options.ts +280 -32
- package/src/types/rules.ts +46 -14
package/src/types/options.ts
CHANGED
|
@@ -2,33 +2,154 @@ import type { DragHandleRule } from './rules.js'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Edge detection presets for common use cases.
|
|
5
|
+
*
|
|
6
|
+
* Edge detection helps you grab parent containers (lists, blockquotes, etc.)
|
|
7
|
+
* by moving the cursor near the edge of a nested element. When the cursor is
|
|
8
|
+
* within the `threshold` zone of a configured edge, the scoring system deducts
|
|
9
|
+
* `strength * depth` from deeper nodes, making the outer container the easier
|
|
10
|
+
* target.
|
|
11
|
+
*
|
|
12
|
+
* In short: cursor near edge prefers parent; cursor centered prefers child.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Left/top edges, natural for LTR layouts (default)
|
|
16
|
+
* DragHandle.configure({
|
|
17
|
+
* nested: {
|
|
18
|
+
* edgeDetection: 'left',
|
|
19
|
+
* },
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Right/top edges, for RTL layouts
|
|
24
|
+
* DragHandle.configure({
|
|
25
|
+
* nested: {
|
|
26
|
+
* edgeDetection: 'right',
|
|
27
|
+
* },
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // No edge detection, cursor position does not affect scoring
|
|
32
|
+
* DragHandle.configure({
|
|
33
|
+
* nested: {
|
|
34
|
+
* edgeDetection: 'none',
|
|
35
|
+
* },
|
|
36
|
+
* })
|
|
5
37
|
*/
|
|
6
38
|
export type EdgeDetectionPreset =
|
|
7
|
-
| 'left' // Prefer parent when cursor near left edge (default)
|
|
8
|
-
| 'right' // Prefer parent when cursor near right edge (RTL support)
|
|
9
|
-
| 'both' // Prefer parent when cursor near
|
|
10
|
-
| 'none' // Disable edge detection entirely
|
|
39
|
+
| 'left' // Prefer parent when cursor near left or top edge (LTR default)
|
|
40
|
+
| 'right' // Prefer parent when cursor near right or top edge (RTL support)
|
|
41
|
+
| 'both' // Prefer parent when cursor near any horizontal edge or top edge
|
|
42
|
+
| 'none' // Disable edge detection entirely, cursor position does not affect scoring
|
|
11
43
|
|
|
12
44
|
/**
|
|
13
|
-
* Advanced edge detection configuration.
|
|
14
|
-
*
|
|
45
|
+
* Advanced edge detection configuration for fine-grained control.
|
|
46
|
+
*
|
|
47
|
+
* Use this interface when the preset strings (\`'left'\`, \`'right'\`, etc.) aren't
|
|
48
|
+
* enough and you need to customize **which edges**, **how wide the zone is**,
|
|
49
|
+
* or **how aggressive** the parent preference should be.
|
|
50
|
+
*
|
|
51
|
+
* Most users should use \`EdgeDetectionPreset\` strings instead of this interface.
|
|
52
|
+
* Only reach for this when you need precise control.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // Wider edge zone, gentler deduction, top/bottom edges only
|
|
56
|
+
* DragHandle.configure({
|
|
57
|
+
* nested: {
|
|
58
|
+
* edgeDetection: {
|
|
59
|
+
* edges: ['top', 'bottom'],
|
|
60
|
+
* threshold: 24,
|
|
61
|
+
* strength: 300,
|
|
62
|
+
* },
|
|
63
|
+
* },
|
|
64
|
+
* })
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Aggressive left-edge only: narrow zone, strong deduction
|
|
68
|
+
* DragHandle.configure({
|
|
69
|
+
* nested: {
|
|
70
|
+
* edgeDetection: {
|
|
71
|
+
* edges: ['left'],
|
|
72
|
+
* threshold: 8,
|
|
73
|
+
* strength: 800,
|
|
74
|
+
* },
|
|
75
|
+
* },
|
|
76
|
+
* })
|
|
15
77
|
*/
|
|
16
78
|
export interface EdgeDetectionConfig {
|
|
17
79
|
/**
|
|
18
80
|
* Which edges trigger parent preference.
|
|
81
|
+
* - `'left'`: Cursor within threshold pixels of the element's left edge
|
|
82
|
+
* - `'right'`: Cursor within threshold pixels of the element's right edge
|
|
83
|
+
* - `'top'`: Cursor within threshold pixels of the element's top edge
|
|
84
|
+
* - `'bottom'`: Cursor within threshold pixels of the element's bottom edge
|
|
85
|
+
*
|
|
19
86
|
* @default ['left', 'top']
|
|
20
87
|
*/
|
|
21
88
|
edges: Array<'left' | 'right' | 'top' | 'bottom'>
|
|
22
89
|
|
|
23
90
|
/**
|
|
24
|
-
* Distance in pixels from edge
|
|
91
|
+
* Distance in pixels from the element edge that triggers the deduction.
|
|
92
|
+
*
|
|
93
|
+
* Think of this as the size of an invisible "edge zone" around the element.
|
|
94
|
+
* When the cursor is inside this zone, `strength * depth` is deducted from
|
|
95
|
+
* deeper nodes, making parent containers easier to grab.
|
|
96
|
+
*
|
|
97
|
+
* - **Higher value** (e.g., 24): The zone is wider, edge detection triggers
|
|
98
|
+
* even when the cursor is relatively far from the element's edge. Parent
|
|
99
|
+
* selection feels more "eager."
|
|
100
|
+
* - **Lower value** (e.g., 6): The zone is narrower, the cursor must be
|
|
101
|
+
* very close to the edge before parent preference kicks in. You need to be
|
|
102
|
+
* more deliberate to grab a parent container.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* // threshold: 12 means the cursor must be within 12px of the edge
|
|
106
|
+
* // threshold: 24 doubles the trigger zone
|
|
107
|
+
*
|
|
25
108
|
* @default 12
|
|
26
109
|
*/
|
|
27
110
|
threshold: number
|
|
28
111
|
|
|
29
112
|
/**
|
|
30
|
-
* How strongly to prefer parent (higher = stronger preference).
|
|
31
|
-
*
|
|
113
|
+
* How strongly to prefer parent nodes near edges (higher = stronger preference).
|
|
114
|
+
*
|
|
115
|
+
* The deduction formula is: `strength * depth`. This means the penalty grows
|
|
116
|
+
* linearly with nesting depth, making deeply nested children less attractive
|
|
117
|
+
* targets when you're near an edge, exactly what you want when trying to
|
|
118
|
+
* grab the outer list rather than the inner paragraph.
|
|
119
|
+
*
|
|
120
|
+
* **Visual guide, default strength (500):**
|
|
121
|
+
* ```
|
|
122
|
+
* Depth | Deduction | Eligible?
|
|
123
|
+
* ──────┼───────────┼──────────
|
|
124
|
+
* 1 | 500 │ Yes, still a valid target
|
|
125
|
+
* 2 | 1000 │ No, penalty matches base score
|
|
126
|
+
* 3 | 1500 │ No, penalty exceeds base score
|
|
127
|
+
* 4 | 2000 │ No, deeply buried
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* **Lower strength (200):**
|
|
131
|
+
* ```
|
|
132
|
+
* Depth | Deduction | Eligible?
|
|
133
|
+
* ──────┼───────────┼──────────
|
|
134
|
+
* 1 | 200 │ Yes
|
|
135
|
+
* 2 | 400 │ Yes
|
|
136
|
+
* 3 | 600 │ Yes
|
|
137
|
+
* 4 | 800 │ Yes (but parent still preferred)
|
|
138
|
+
* 5 | 1000 │ No, excluded at threshold
|
|
139
|
+
* ```
|
|
140
|
+
* Good when you want edge detection to nudge toward parents without
|
|
141
|
+
* excluding typical nesting depths.
|
|
142
|
+
*
|
|
143
|
+
* **Higher strength (1000):**
|
|
144
|
+
* ```
|
|
145
|
+
* Depth | Deduction | Eligible?
|
|
146
|
+
* ──────┼───────────┼──────────
|
|
147
|
+
* 1 | 1000 │ No, excluded at threshold
|
|
148
|
+
* ```
|
|
149
|
+
* Every non-doc candidate near the edge is excluded from being a drag
|
|
150
|
+
* target. Use when you want edge detection to completely disable nested
|
|
151
|
+
* dragging near the edges and force root-level handles.
|
|
152
|
+
*
|
|
32
153
|
* @default 500
|
|
33
154
|
*/
|
|
34
155
|
strength: number
|
|
@@ -36,13 +157,69 @@ export interface EdgeDetectionConfig {
|
|
|
36
157
|
|
|
37
158
|
/**
|
|
38
159
|
* Configuration for nested drag handle behavior.
|
|
160
|
+
*
|
|
161
|
+
* When enabled, the drag handle can target nodes at any depth in the document
|
|
162
|
+
* tree (not just top-level blocks). A rule-based scoring system evaluates all
|
|
163
|
+
* ancestor nodes at the cursor position and selects the best drag target.
|
|
164
|
+
*
|
|
165
|
+
* **How the scoring works:**
|
|
166
|
+
* 1. Each ancestor node at the cursor position starts with a base score of 1000
|
|
167
|
+
* 2. Default rules are applied first (subtracting deductions for lists, tables, etc.)
|
|
168
|
+
* 3. Your custom rules are applied next (for app-specific logic)
|
|
169
|
+
* 4. Edge detection adds a final deduction (`strength * depth`) when near element edges
|
|
170
|
+
* 5. The highest-scoring node wins; ties are broken by depth (deeper nodes win)
|
|
171
|
+
* 6. Any node with a score of 0 or below is excluded as a drag target
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* // Simple enable with sensible defaults
|
|
175
|
+
* DragHandle.configure({
|
|
176
|
+
* nested: true,
|
|
177
|
+
* })
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* // Full custom configuration
|
|
181
|
+
* DragHandle.configure({
|
|
182
|
+
* nested: {
|
|
183
|
+
* defaultRules: true,
|
|
184
|
+
* allowedContainers: ['bulletList', 'orderedList', 'blockquote'],
|
|
185
|
+
* edgeDetection: 'left',
|
|
186
|
+
* rules: [
|
|
187
|
+
* {
|
|
188
|
+
* id: 'myCustomRule',
|
|
189
|
+
* evaluate: ({ node }) =>
|
|
190
|
+
* node.type.name === 'myCustomBlock' ? 1000 : 0,
|
|
191
|
+
* },
|
|
192
|
+
* ],
|
|
193
|
+
* },
|
|
194
|
+
* })
|
|
39
195
|
*/
|
|
40
196
|
export interface NestedOptions {
|
|
41
197
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
198
|
+
* Custom rules that determine which nodes are draggable.
|
|
199
|
+
*
|
|
200
|
+
* Rules are evaluated AFTER the default rules. Each rule receives a
|
|
201
|
+
* `RuleContext` and returns a score deduction:
|
|
202
|
+
* - `0`: No effect, node remains fully eligible
|
|
203
|
+
* - `1-999`: Partial deduction, node is less preferred but still eligible
|
|
204
|
+
* - `>= 1000`: Node is **excluded** from being a drag target
|
|
205
|
+
*
|
|
206
|
+
* Common use cases for custom rules:
|
|
207
|
+
* - Exclude specific node types from being draggable
|
|
208
|
+
* - Deprioritize certain nodes with partial deductions
|
|
209
|
+
* - Scope dragging to specific document structures
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* // Exclude code blocks from being draggable
|
|
213
|
+
* rules: [
|
|
214
|
+
* {
|
|
215
|
+
* id: 'excludeCodeBlocks',
|
|
216
|
+
* evaluate: ({ node }) =>
|
|
217
|
+
* node.type.name === 'codeBlock' ? 1000 : 0,
|
|
218
|
+
* },
|
|
219
|
+
* ]
|
|
44
220
|
*
|
|
45
221
|
* @example
|
|
222
|
+
* // Inside a custom "question" block, only allow dragging "alternative" children
|
|
46
223
|
* rules: [
|
|
47
224
|
* {
|
|
48
225
|
* id: 'onlyAlternatives',
|
|
@@ -54,64 +231,135 @@ export interface NestedOptions {
|
|
|
54
231
|
* },
|
|
55
232
|
* },
|
|
56
233
|
* ]
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* // Deprioritize deeper nodes with partial deduction
|
|
237
|
+
* rules: [
|
|
238
|
+
* {
|
|
239
|
+
* id: 'preferShallow',
|
|
240
|
+
* evaluate: ({ depth }) => depth * 100,
|
|
241
|
+
* },
|
|
242
|
+
* ]
|
|
57
243
|
*/
|
|
58
244
|
rules?: DragHandleRule[]
|
|
59
245
|
|
|
60
246
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
247
|
+
* Whether to include the built-in default rules before your custom rules.
|
|
248
|
+
*
|
|
249
|
+
* The default rules handle common editor patterns:
|
|
250
|
+
* - \`listItemFirstChild\` -- Excludes the first child of listItem/taskItem
|
|
251
|
+
* (the content paragraph), so the list item itself is the drag target
|
|
252
|
+
* - \`listWrapperDeprioritize\` -- Excludes bulletList/orderedList wrappers,
|
|
253
|
+
* so individual list items are the default drag target
|
|
254
|
+
* - \`tableStructure\` -- Excludes tableRow, tableCell, tableHeader from dragging
|
|
255
|
+
* (table extensions handle their own drag behavior)
|
|
256
|
+
* - \`inlineContent\` -- Excludes inline nodes and text from being drag targets
|
|
257
|
+
*
|
|
258
|
+
* Set to `false` to disable all default rules and use only your custom `rules`.
|
|
259
|
+
* This is useful when the default behavior conflicts with your custom setup.
|
|
63
260
|
*
|
|
64
261
|
* @default true
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* // Use only your own rule, no defaults
|
|
265
|
+
* nested: {
|
|
266
|
+
* defaultRules: false,
|
|
267
|
+
* rules: [{
|
|
268
|
+
* id: 'onlyParagraphs',
|
|
269
|
+
* evaluate: ({ node }) =>
|
|
270
|
+
* node.type.name === 'paragraph' ? 0 : 1000,
|
|
271
|
+
* }],
|
|
272
|
+
* }
|
|
65
273
|
*/
|
|
66
274
|
defaultRules?: boolean
|
|
67
275
|
|
|
68
276
|
/**
|
|
69
|
-
* Restrict nested drag handles to specific container types.
|
|
70
|
-
*
|
|
277
|
+
* Restrict nested drag handles to specific container node types.
|
|
278
|
+
*
|
|
279
|
+
* When set, nested dragging only activates when the cursor is inside one of
|
|
280
|
+
* the specified node types (at any ancestor level). When the cursor is
|
|
281
|
+
* outside these containers, the drag handle hides entirely for nested
|
|
282
|
+
* content positioned inside those regions.
|
|
283
|
+
*
|
|
284
|
+
* This is useful for scoping nested drag handles to specific editor regions
|
|
285
|
+
* (e.g., lists and blockquotes) while keeping simpler blocks (headings,
|
|
286
|
+
* paragraphs) working with only top-level handles.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* // Only enable nested dragging inside lists
|
|
290
|
+
* allowedContainers: ['bulletList', 'orderedList']
|
|
71
291
|
*
|
|
72
292
|
* @example
|
|
73
|
-
* //
|
|
74
|
-
* allowedContainers: ['bulletList', 'orderedList', '
|
|
293
|
+
* // Enable nested dragging inside lists and blockquotes
|
|
294
|
+
* allowedContainers: ['bulletList', 'orderedList', 'blockquote']
|
|
75
295
|
*/
|
|
76
296
|
allowedContainers?: string[]
|
|
77
297
|
|
|
78
298
|
/**
|
|
79
|
-
*
|
|
299
|
+
* Controls when the drag handle prefers a parent node over a deeply nested
|
|
300
|
+
* child node, based on cursor proximity to element edges.
|
|
301
|
+
*
|
|
302
|
+
* When the cursor is near a configured edge of a nested element, the scoring
|
|
303
|
+
* system deducts \`strength * depth\` from deeper nodes, making the parent
|
|
304
|
+
* container (like an entire list) easier to grab.
|
|
305
|
+
*
|
|
306
|
+
* **Presets (quick and simple):**
|
|
307
|
+
* - `'left'` (default): Cursor near left or top edge → prefer parent (LTR)
|
|
308
|
+
* - `'right'`: Cursor near right or top edge → prefer parent (RTL)
|
|
309
|
+
* - `'both'`: Cursor near left, right, or top edge → prefer parent
|
|
310
|
+
* - \`'none'\`: Disabled, cursor position does not affect scoring at all
|
|
80
311
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* - `
|
|
84
|
-
* - `
|
|
85
|
-
* - `
|
|
312
|
+
* **Fine-tuned object (full control):**
|
|
313
|
+
* Pass a partial `EdgeDetectionConfig` to override only what you need:
|
|
314
|
+
* - `edges`: Which element edges trigger parent preference (default: `['left', 'top']`)
|
|
315
|
+
* - `threshold`: Width of the edge zone in pixels (default: `12`). Higher = easier to trigger.
|
|
316
|
+
* - `strength`: Deduction multiplier per depth level (default: `500`). Higher = stronger parent preference.
|
|
86
317
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
318
|
+
* The effective deduction when near an edge is `strength * depth`, so deeper
|
|
319
|
+
* nesting always gets penalized more, you naturally grab the outer wrapper.
|
|
89
320
|
*
|
|
90
321
|
* @default 'left'
|
|
91
322
|
*
|
|
92
323
|
* @example
|
|
93
|
-
* //
|
|
94
|
-
* edgeDetection: { threshold:
|
|
324
|
+
* // Just widen the trigger zone to 24px
|
|
325
|
+
* edgeDetection: { threshold: 24 }
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* // Top/bottom edges only, very aggressive parent preference
|
|
329
|
+
* edgeDetection: {
|
|
330
|
+
* edges: ['top', 'bottom'],
|
|
331
|
+
* threshold: 30,
|
|
332
|
+
* strength: 1000,
|
|
333
|
+
* }
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* // Gentle edge detection, nudges toward parents without blocking typical depths
|
|
337
|
+
* edgeDetection: {
|
|
338
|
+
* threshold: 6,
|
|
339
|
+
* strength: 200,
|
|
340
|
+
* }
|
|
95
341
|
*/
|
|
96
342
|
edgeDetection?: EdgeDetectionPreset | Partial<EdgeDetectionConfig>
|
|
97
343
|
}
|
|
98
344
|
|
|
99
345
|
/**
|
|
100
|
-
*
|
|
346
|
+
* Fully resolved nested drag handle options after normalization.
|
|
347
|
+
* Produced by `normalizeNestedOptions()` from user-provided `NestedOptions`
|
|
348
|
+
* or a boolean flag. This is the internal representation consumed by the plugin.
|
|
101
349
|
*/
|
|
102
350
|
export interface NormalizedNestedOptions {
|
|
103
351
|
/** Whether nested drag handles are enabled */
|
|
104
352
|
enabled: boolean
|
|
105
353
|
|
|
106
|
-
/** Custom rules to apply */
|
|
354
|
+
/** Custom rules to apply (combined with default rules if `defaultRules` is true) */
|
|
107
355
|
rules: DragHandleRule[]
|
|
108
356
|
|
|
109
|
-
/** Whether
|
|
357
|
+
/** Whether the built-in default rules are included alongside custom rules */
|
|
110
358
|
defaultRules: boolean
|
|
111
359
|
|
|
112
|
-
/** Allowed container node types
|
|
360
|
+
/** Allowed container node types, or `undefined` to allow all containers */
|
|
113
361
|
allowedContainers: string[] | undefined
|
|
114
362
|
|
|
115
|
-
/**
|
|
363
|
+
/** Fully resolved edge detection configuration with all defaults applied */
|
|
116
364
|
edgeDetection: EdgeDetectionConfig
|
|
117
365
|
}
|
package/src/types/rules.ts
CHANGED
|
@@ -2,52 +2,86 @@ import type { Node, ResolvedPos } from '@tiptap/pm/model'
|
|
|
2
2
|
import type { EditorView } from '@tiptap/pm/view'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Context provided to each rule
|
|
6
|
-
*
|
|
5
|
+
* Context provided to each rule evaluation function.
|
|
6
|
+
*
|
|
7
|
+
* Contains information about the node being evaluated and its position in the
|
|
8
|
+
* ProseMirror document tree. This is the full context available for making
|
|
9
|
+
* scoring decisions in custom `DragHandleRule` implementations.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Typical usage in a custom rule
|
|
13
|
+
* evaluate: ({ node, parent, depth, isFirst }) => {
|
|
14
|
+
* if (parent?.type.name === 'listItem' && isFirst) {
|
|
15
|
+
* return 1000 // exclude first child of list items
|
|
16
|
+
* }
|
|
17
|
+
* if (depth > 3) {
|
|
18
|
+
* return depth * 200 // deprioritize deep nesting
|
|
19
|
+
* }
|
|
20
|
+
* return 0
|
|
21
|
+
* }
|
|
7
22
|
*/
|
|
8
23
|
export interface RuleContext {
|
|
9
|
-
/** The node being evaluated */
|
|
24
|
+
/** The ProseMirror node being evaluated as a potential drag target */
|
|
10
25
|
node: Node
|
|
11
26
|
|
|
12
27
|
/** Absolute position of the node in the document */
|
|
13
28
|
pos: number
|
|
14
29
|
|
|
15
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Depth in the document tree (0 = document root).
|
|
32
|
+
* A paragraph inside a listItem inside a bulletList has depth 3.
|
|
33
|
+
*/
|
|
16
34
|
depth: number
|
|
17
35
|
|
|
18
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Parent node of the node being evaluated.
|
|
38
|
+
* `null` if the node is the document root (depth 0).
|
|
39
|
+
*/
|
|
19
40
|
parent: Node | null
|
|
20
41
|
|
|
21
|
-
/** This node's index among
|
|
42
|
+
/** This node's index among its parent's children (0-based) */
|
|
22
43
|
index: number
|
|
23
44
|
|
|
24
|
-
/** Convenience: true
|
|
45
|
+
/** Convenience: `true` when this node is the first child of its parent (index === 0) */
|
|
25
46
|
isFirst: boolean
|
|
26
47
|
|
|
27
|
-
/** Convenience: true
|
|
48
|
+
/** Convenience: `true` when this node is the last child of its parent */
|
|
28
49
|
isLast: boolean
|
|
29
50
|
|
|
30
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* The resolved position for advanced ProseMirror queries.
|
|
53
|
+
* Allows access to ancestor nodes, child nodes, and document structure
|
|
54
|
+
* beyond the current node.
|
|
55
|
+
*/
|
|
31
56
|
$pos: ResolvedPos
|
|
32
57
|
|
|
33
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* The editor view for DOM access if needed in custom rules.
|
|
60
|
+
* Can be used to access the editor DOM element, measure dimensions, etc.
|
|
61
|
+
*/
|
|
34
62
|
view: EditorView
|
|
35
63
|
}
|
|
36
64
|
|
|
37
65
|
/**
|
|
38
66
|
* A rule that determines whether a node should be a drag target.
|
|
67
|
+
*
|
|
68
|
+
* Each rule receives a `RuleContext` and returns a numeric deduction.
|
|
69
|
+
* Multiple rules are evaluated in sequence; the total deduction is subtracted
|
|
70
|
+
* from the node's base score (1000). If the score drops to 0 or below,
|
|
71
|
+
* the node is excluded as a drag target.
|
|
39
72
|
*/
|
|
40
73
|
export interface DragHandleRule {
|
|
41
74
|
/**
|
|
42
75
|
* Unique identifier for debugging and rule management.
|
|
76
|
+
* Choose a descriptive name that explains what the rule does.
|
|
43
77
|
*/
|
|
44
78
|
id: string
|
|
45
79
|
|
|
46
80
|
/**
|
|
47
81
|
* Evaluate the node and return a score deduction.
|
|
48
82
|
*
|
|
49
|
-
* The return value is subtracted from the node's score (
|
|
50
|
-
* Higher deductions make the node less likely to be selected
|
|
83
|
+
* The return value is subtracted from the node's base score (1000).
|
|
84
|
+
* Higher deductions make the node less likely to be selected.
|
|
51
85
|
*
|
|
52
86
|
* @returns A number representing the score deduction:
|
|
53
87
|
* - `0` - No deduction, node remains fully eligible
|
|
@@ -66,7 +100,6 @@ export interface DragHandleRule {
|
|
|
66
100
|
* @example
|
|
67
101
|
* // Prefer shallower nodes with partial deduction
|
|
68
102
|
* evaluate: ({ depth }) => {
|
|
69
|
-
* // Deeper nodes get small deductions, making shallower nodes win ties
|
|
70
103
|
* return depth * 50
|
|
71
104
|
* }
|
|
72
105
|
*
|
|
@@ -74,7 +107,6 @@ export interface DragHandleRule {
|
|
|
74
107
|
* // Context-based partial deductions
|
|
75
108
|
* evaluate: ({ node, parent }) => {
|
|
76
109
|
* if (parent?.type.name === 'tableCell') {
|
|
77
|
-
* // Inside table cells, slightly prefer the cell over its content
|
|
78
110
|
* return node.type.name === 'paragraph' ? 100 : 0
|
|
79
111
|
* }
|
|
80
112
|
* return 0
|