@rtif-sdk/web 1.4.0 → 1.6.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.
- package/dist/block-drag-handler.d.ts +26 -0
- package/dist/block-drag-handler.d.ts.map +1 -1
- package/dist/block-drag-handler.js +33 -23
- package/dist/block-drag-handler.js.map +1 -1
- package/dist/block-gutter.d.ts +81 -0
- package/dist/block-gutter.d.ts.map +1 -0
- package/dist/block-gutter.js +331 -0
- package/dist/block-gutter.js.map +1 -0
- package/dist/context-menu.d.ts +54 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +470 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/drop-indicator.d.ts.map +1 -1
- package/dist/drop-indicator.js +8 -34
- package/dist/drop-indicator.js.map +1 -1
- package/dist/editor.d.ts +1 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +153 -12
- package/dist/editor.js.map +1 -1
- package/dist/floating-toolbar.d.ts.map +1 -1
- package/dist/floating-toolbar.js +4 -7
- package/dist/floating-toolbar.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/link-popover.d.ts.map +1 -1
- package/dist/link-popover.js +2 -43
- package/dist/link-popover.js.map +1 -1
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +27 -5
- package/dist/renderer.js.map +1 -1
- package/dist/selection-sync.d.ts.map +1 -1
- package/dist/selection-sync.js +20 -3
- package/dist/selection-sync.js.map +1 -1
- package/dist/types.d.ts +208 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -4
- package/styles/all.css +21 -0
- package/styles/base.css +33 -0
- package/styles/block-gutter.css +76 -0
- package/styles/blocks.css +199 -0
- package/styles/context-menu.css +58 -0
- package/styles/drop-indicator.css +37 -0
- package/styles/floating-toolbar.css +51 -0
- package/styles/link-popover.css +64 -0
- package/styles/marks.css +27 -0
- package/styles/mention.css +17 -0
- package/styles/pickers.css +317 -0
- package/styles/toolbar.css +151 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block gutter toolbar — a Notion-style hover-revealed toolbar to the left
|
|
3
|
+
* of blocks with a "+" button (add block below) and a drag handle (reorder).
|
|
4
|
+
*
|
|
5
|
+
* The gutter owns hover detection and DOM elements. Drag-and-drop logic is
|
|
6
|
+
* delegated to {@link BlockDragHandler} in external handle mode.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { blockTextLength } from '@rtif-sdk/core';
|
|
11
|
+
import { BlockDragHandler, findBlockElement } from './block-drag-handler.js';
|
|
12
|
+
import { getBlockStartOffset } from './plugins/block-utils.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// CSS class names
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const CSS_GUTTER = 'rtif-block-gutter';
|
|
17
|
+
const CSS_ADD = 'rtif-gutter-add';
|
|
18
|
+
const CSS_HANDLE = 'rtif-drag-handle';
|
|
19
|
+
const CSS_HIDDEN = 'rtif-hidden';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Factory
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Create a block gutter toolbar.
|
|
25
|
+
*
|
|
26
|
+
* The gutter appears on hover or when the keyboard cursor enters a block.
|
|
27
|
+
* It provides a "+" button to add a new block below and a drag handle
|
|
28
|
+
* for block reordering.
|
|
29
|
+
*
|
|
30
|
+
* @param deps - Injected dependencies
|
|
31
|
+
* @returns A handle to attach/detach the gutter
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const gutter = createBlockGutter({
|
|
36
|
+
* root: editorRoot,
|
|
37
|
+
* engine,
|
|
38
|
+
* isReadOnly: () => false,
|
|
39
|
+
* getBlockElementMap: () => blockElementMap,
|
|
40
|
+
* generateBlockId: () => generateId(),
|
|
41
|
+
* focusAtOffset: (offset) => { ... },
|
|
42
|
+
* });
|
|
43
|
+
* gutter.attach();
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function createBlockGutter(deps) {
|
|
47
|
+
let attached = false;
|
|
48
|
+
// Active block state
|
|
49
|
+
let activeBlockId = null;
|
|
50
|
+
let mouseIsActive = false;
|
|
51
|
+
let isDragging = false;
|
|
52
|
+
let hideTimeout = null;
|
|
53
|
+
let rafId = null;
|
|
54
|
+
// -------------------------------------------------------------------------
|
|
55
|
+
// DOM creation
|
|
56
|
+
// -------------------------------------------------------------------------
|
|
57
|
+
const gutterEl = document.createElement('div');
|
|
58
|
+
gutterEl.className = CSS_GUTTER;
|
|
59
|
+
gutterEl.setAttribute('role', 'toolbar');
|
|
60
|
+
gutterEl.setAttribute('aria-label', 'Block actions');
|
|
61
|
+
gutterEl.setAttribute('contenteditable', 'false');
|
|
62
|
+
gutterEl.classList.add(CSS_HIDDEN);
|
|
63
|
+
// + button
|
|
64
|
+
const addButton = document.createElement('button');
|
|
65
|
+
addButton.className = CSS_ADD;
|
|
66
|
+
addButton.type = 'button';
|
|
67
|
+
addButton.setAttribute('aria-label', 'Add block below');
|
|
68
|
+
addButton.textContent = '+';
|
|
69
|
+
// Drag handle
|
|
70
|
+
const dragHandle = document.createElement('div');
|
|
71
|
+
dragHandle.className = CSS_HANDLE;
|
|
72
|
+
dragHandle.setAttribute('draggable', 'true');
|
|
73
|
+
dragHandle.setAttribute('role', 'button');
|
|
74
|
+
dragHandle.setAttribute('tabindex', '-1');
|
|
75
|
+
dragHandle.setAttribute('aria-label', 'Drag to reorder');
|
|
76
|
+
dragHandle.textContent = '\u2807'; // BRAILLE PATTERN DOTS-123
|
|
77
|
+
gutterEl.appendChild(addButton);
|
|
78
|
+
gutterEl.appendChild(dragHandle);
|
|
79
|
+
// -------------------------------------------------------------------------
|
|
80
|
+
// BlockDragHandler in external handle mode
|
|
81
|
+
// -------------------------------------------------------------------------
|
|
82
|
+
const blockDragHandler = new BlockDragHandler({
|
|
83
|
+
root: deps.root,
|
|
84
|
+
getDoc: () => deps.engine.state.doc,
|
|
85
|
+
dispatch: (ops) => deps.engine.dispatch(ops),
|
|
86
|
+
isReadOnly: deps.isReadOnly,
|
|
87
|
+
getBlockElementMap: () => deps.getBlockElementMap(),
|
|
88
|
+
externalHandleMode: true,
|
|
89
|
+
getHandleEl: () => dragHandle,
|
|
90
|
+
});
|
|
91
|
+
// -------------------------------------------------------------------------
|
|
92
|
+
// Gutter positioning
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
function showGutter(blockEl) {
|
|
95
|
+
if (deps.isReadOnly())
|
|
96
|
+
return;
|
|
97
|
+
if (isDragging)
|
|
98
|
+
return;
|
|
99
|
+
const blockId = blockEl.getAttribute('data-rtif-block');
|
|
100
|
+
if (!blockId)
|
|
101
|
+
return;
|
|
102
|
+
activeBlockId = blockId;
|
|
103
|
+
dragHandle.setAttribute('data-drag-block-id', blockId);
|
|
104
|
+
const rootRect = deps.root.getBoundingClientRect();
|
|
105
|
+
const blockRect = blockEl.getBoundingClientRect();
|
|
106
|
+
// Account for scroll offset: getBoundingClientRect is viewport-relative,
|
|
107
|
+
// but absolute positioning is relative to the offsetParent (root).
|
|
108
|
+
// When the root is scrolled, we need to add scrollTop to compensate.
|
|
109
|
+
gutterEl.style.top = `${blockRect.top - rootRect.top + deps.root.scrollTop}px`;
|
|
110
|
+
gutterEl.style.height = `${blockRect.height}px`;
|
|
111
|
+
gutterEl.classList.remove(CSS_HIDDEN);
|
|
112
|
+
}
|
|
113
|
+
function hideGutter() {
|
|
114
|
+
gutterEl.classList.add(CSS_HIDDEN);
|
|
115
|
+
activeBlockId = null;
|
|
116
|
+
}
|
|
117
|
+
function clearHideTimeout() {
|
|
118
|
+
if (hideTimeout !== null) {
|
|
119
|
+
clearTimeout(hideTimeout);
|
|
120
|
+
hideTimeout = null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function scheduleHide() {
|
|
124
|
+
clearHideTimeout();
|
|
125
|
+
hideTimeout = setTimeout(() => {
|
|
126
|
+
hideTimeout = null;
|
|
127
|
+
hideGutter();
|
|
128
|
+
mouseIsActive = false;
|
|
129
|
+
}, 150);
|
|
130
|
+
}
|
|
131
|
+
// -------------------------------------------------------------------------
|
|
132
|
+
// Hover detection (event delegation on root)
|
|
133
|
+
// -------------------------------------------------------------------------
|
|
134
|
+
function onMouseOver(e) {
|
|
135
|
+
const blockEl = findBlockElement(e.target, deps.root);
|
|
136
|
+
if (blockEl) {
|
|
137
|
+
clearHideTimeout();
|
|
138
|
+
mouseIsActive = true;
|
|
139
|
+
showGutter(blockEl);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function onMouseOut(e) {
|
|
143
|
+
const relatedTarget = e.relatedTarget;
|
|
144
|
+
if (relatedTarget) {
|
|
145
|
+
// Moving to gutter → grace
|
|
146
|
+
if (gutterEl.contains(relatedTarget))
|
|
147
|
+
return;
|
|
148
|
+
// Moving to another block → will trigger mouseover
|
|
149
|
+
if (deps.root.contains(relatedTarget)) {
|
|
150
|
+
const blockEl = findBlockElement(relatedTarget, deps.root);
|
|
151
|
+
if (blockEl)
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
scheduleHide();
|
|
156
|
+
}
|
|
157
|
+
function onGutterMouseEnter() {
|
|
158
|
+
clearHideTimeout();
|
|
159
|
+
}
|
|
160
|
+
function onGutterMouseLeave(e) {
|
|
161
|
+
const relatedTarget = e.relatedTarget;
|
|
162
|
+
if (relatedTarget && deps.root.contains(relatedTarget)) {
|
|
163
|
+
const blockEl = findBlockElement(relatedTarget, deps.root);
|
|
164
|
+
if (blockEl)
|
|
165
|
+
return; // Moving back to a block
|
|
166
|
+
}
|
|
167
|
+
scheduleHide();
|
|
168
|
+
}
|
|
169
|
+
// -------------------------------------------------------------------------
|
|
170
|
+
// Drag state tracking — hide gutter during active drag
|
|
171
|
+
// -------------------------------------------------------------------------
|
|
172
|
+
function onDragStart() {
|
|
173
|
+
isDragging = true;
|
|
174
|
+
hideGutter();
|
|
175
|
+
}
|
|
176
|
+
function onDragEnd() {
|
|
177
|
+
isDragging = false;
|
|
178
|
+
}
|
|
179
|
+
// -------------------------------------------------------------------------
|
|
180
|
+
// Keyboard focus tracking (rAF-throttled)
|
|
181
|
+
// -------------------------------------------------------------------------
|
|
182
|
+
let prevFocusBlockId = null;
|
|
183
|
+
let unsubChange = null;
|
|
184
|
+
let unsubSelection = null;
|
|
185
|
+
function updateGutterForSelection() {
|
|
186
|
+
if (deps.isReadOnly())
|
|
187
|
+
return;
|
|
188
|
+
// Mouse hover takes priority
|
|
189
|
+
if (mouseIsActive)
|
|
190
|
+
return;
|
|
191
|
+
if (isDragging)
|
|
192
|
+
return;
|
|
193
|
+
const { selection, doc } = deps.engine.state;
|
|
194
|
+
const offset = selection.focus.offset;
|
|
195
|
+
try {
|
|
196
|
+
const block = deps.engine.getBlockAtOffset(offset);
|
|
197
|
+
if (block.id === prevFocusBlockId)
|
|
198
|
+
return;
|
|
199
|
+
prevFocusBlockId = block.id;
|
|
200
|
+
const blockEl = deps.getBlockElementMap().get(block.id);
|
|
201
|
+
if (!blockEl)
|
|
202
|
+
return; // Virtualized away
|
|
203
|
+
showGutter(blockEl);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Offset out of range — hide
|
|
207
|
+
hideGutter();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function scheduleSelectionUpdate() {
|
|
211
|
+
if (rafId !== null)
|
|
212
|
+
return; // Already scheduled
|
|
213
|
+
rafId = requestAnimationFrame(() => {
|
|
214
|
+
rafId = null;
|
|
215
|
+
updateGutterForSelection();
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
// -------------------------------------------------------------------------
|
|
219
|
+
// + button handler
|
|
220
|
+
// -------------------------------------------------------------------------
|
|
221
|
+
function onAddMouseDown(e) {
|
|
222
|
+
e.preventDefault(); // Preserve editor focus
|
|
223
|
+
}
|
|
224
|
+
function onAddClick() {
|
|
225
|
+
if (deps.isReadOnly())
|
|
226
|
+
return;
|
|
227
|
+
if (!activeBlockId)
|
|
228
|
+
return;
|
|
229
|
+
const doc = deps.engine.state.doc;
|
|
230
|
+
const block = doc.blocks.find((b) => b.id === activeBlockId);
|
|
231
|
+
if (!block)
|
|
232
|
+
return;
|
|
233
|
+
const blockStart = getBlockStartOffset(doc, activeBlockId);
|
|
234
|
+
const blockLen = blockTextLength(block);
|
|
235
|
+
const splitOffset = blockStart + blockLen;
|
|
236
|
+
const newBlockId = deps.generateBlockId();
|
|
237
|
+
deps.engine.dispatch({
|
|
238
|
+
type: 'split_block',
|
|
239
|
+
offset: splitOffset,
|
|
240
|
+
newBlockId,
|
|
241
|
+
});
|
|
242
|
+
// Cursor at start of new block (splitOffset + 1 for virtual \n)
|
|
243
|
+
deps.focusAtOffset(splitOffset + 1);
|
|
244
|
+
}
|
|
245
|
+
// Drag handle also needs focus preservation
|
|
246
|
+
function onDragHandleMouseDown(e) {
|
|
247
|
+
e.preventDefault();
|
|
248
|
+
}
|
|
249
|
+
// -------------------------------------------------------------------------
|
|
250
|
+
// Blur handler
|
|
251
|
+
// -------------------------------------------------------------------------
|
|
252
|
+
function onBlur() {
|
|
253
|
+
clearHideTimeout();
|
|
254
|
+
hideGutter();
|
|
255
|
+
mouseIsActive = false;
|
|
256
|
+
prevFocusBlockId = null;
|
|
257
|
+
}
|
|
258
|
+
// -------------------------------------------------------------------------
|
|
259
|
+
// Lifecycle
|
|
260
|
+
// -------------------------------------------------------------------------
|
|
261
|
+
return {
|
|
262
|
+
attach() {
|
|
263
|
+
if (attached)
|
|
264
|
+
return;
|
|
265
|
+
attached = true;
|
|
266
|
+
// Append gutter to root
|
|
267
|
+
deps.root.appendChild(gutterEl);
|
|
268
|
+
// Hover listeners
|
|
269
|
+
deps.root.addEventListener('mouseover', onMouseOver);
|
|
270
|
+
deps.root.addEventListener('mouseout', onMouseOut);
|
|
271
|
+
gutterEl.addEventListener('mouseenter', onGutterMouseEnter);
|
|
272
|
+
gutterEl.addEventListener('mouseleave', onGutterMouseLeave);
|
|
273
|
+
// Button listeners
|
|
274
|
+
addButton.addEventListener('mousedown', onAddMouseDown);
|
|
275
|
+
addButton.addEventListener('click', onAddClick);
|
|
276
|
+
dragHandle.addEventListener('mousedown', onDragHandleMouseDown);
|
|
277
|
+
// Drag state listeners
|
|
278
|
+
deps.root.addEventListener('dragstart', onDragStart);
|
|
279
|
+
deps.root.addEventListener('dragend', onDragEnd);
|
|
280
|
+
// Blur
|
|
281
|
+
deps.root.addEventListener('blur', onBlur);
|
|
282
|
+
// Keyboard tracking (rAF-throttled)
|
|
283
|
+
unsubChange = deps.engine.onChange(() => scheduleSelectionUpdate());
|
|
284
|
+
unsubSelection = deps.engine.onSelectionChange(() => scheduleSelectionUpdate());
|
|
285
|
+
// Drag handler
|
|
286
|
+
blockDragHandler.attach();
|
|
287
|
+
},
|
|
288
|
+
detach() {
|
|
289
|
+
if (!attached)
|
|
290
|
+
return;
|
|
291
|
+
attached = false;
|
|
292
|
+
// Hover listeners
|
|
293
|
+
deps.root.removeEventListener('mouseover', onMouseOver);
|
|
294
|
+
deps.root.removeEventListener('mouseout', onMouseOut);
|
|
295
|
+
gutterEl.removeEventListener('mouseenter', onGutterMouseEnter);
|
|
296
|
+
gutterEl.removeEventListener('mouseleave', onGutterMouseLeave);
|
|
297
|
+
// Button listeners
|
|
298
|
+
addButton.removeEventListener('mousedown', onAddMouseDown);
|
|
299
|
+
addButton.removeEventListener('click', onAddClick);
|
|
300
|
+
dragHandle.removeEventListener('mousedown', onDragHandleMouseDown);
|
|
301
|
+
// Drag state listeners
|
|
302
|
+
deps.root.removeEventListener('dragstart', onDragStart);
|
|
303
|
+
deps.root.removeEventListener('dragend', onDragEnd);
|
|
304
|
+
// Blur
|
|
305
|
+
deps.root.removeEventListener('blur', onBlur);
|
|
306
|
+
// Keyboard tracking
|
|
307
|
+
unsubChange?.();
|
|
308
|
+
unsubSelection?.();
|
|
309
|
+
unsubChange = null;
|
|
310
|
+
unsubSelection = null;
|
|
311
|
+
// Cancel pending rAF
|
|
312
|
+
if (rafId !== null) {
|
|
313
|
+
cancelAnimationFrame(rafId);
|
|
314
|
+
rafId = null;
|
|
315
|
+
}
|
|
316
|
+
// Drag handler
|
|
317
|
+
blockDragHandler.detach();
|
|
318
|
+
// Remove DOM
|
|
319
|
+
if (gutterEl.parentNode) {
|
|
320
|
+
gutterEl.parentNode.removeChild(gutterEl);
|
|
321
|
+
}
|
|
322
|
+
// Clear state
|
|
323
|
+
clearHideTimeout();
|
|
324
|
+
activeBlockId = null;
|
|
325
|
+
mouseIsActive = false;
|
|
326
|
+
isDragging = false;
|
|
327
|
+
prevFocusBlockId = null;
|
|
328
|
+
},
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=block-gutter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-gutter.js","sourceRoot":"","sources":["../src/block-gutter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,MAAM,UAAU,GAAG,mBAAmB,CAAC;AACvC,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAClC,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACtC,MAAM,UAAU,GAAG,aAAa,CAAC;AA4DjC,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,qBAAqB;IACrB,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,WAAW,GAAyC,IAAI,CAAC;IAC7D,IAAI,KAAK,GAAkB,IAAI,CAAC;IAEhC,4EAA4E;IAC5E,eAAe;IACf,4EAA4E;IAE5E,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC/C,QAAQ,CAAC,SAAS,GAAG,UAAU,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,QAAQ,CAAC,YAAY,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IACrD,QAAQ,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAClD,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAEnC,WAAW;IACX,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACnD,SAAS,CAAC,SAAS,GAAG,OAAO,CAAC;IAC9B,SAAS,CAAC,IAAI,GAAG,QAAQ,CAAC;IAC1B,SAAS,CAAC,YAAY,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IACxD,SAAS,CAAC,WAAW,GAAG,GAAG,CAAC;IAE5B,cAAc;IACd,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACjD,UAAU,CAAC,SAAS,GAAG,UAAU,CAAC;IAClC,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC7C,UAAU,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,UAAU,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC1C,UAAU,CAAC,YAAY,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IACzD,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC,CAAC,2BAA2B;IAE9D,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAEjC,4EAA4E;IAC5E,2CAA2C;IAC3C,4EAA4E;IAE5E,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,CAAC;QAC5C,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG;QACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC5C,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,kBAAkB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE;QACnD,kBAAkB,EAAE,IAAI;QACxB,WAAW,EAAE,GAAG,EAAE,CAAC,UAAU;KAC9B,CAAC,CAAC;IAEH,4EAA4E;IAC5E,qBAAqB;IACrB,4EAA4E;IAE5E,SAAS,UAAU,CAAC,OAAgB;QAClC,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO;QAC9B,IAAI,UAAU;YAAE,OAAO;QAEvB,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,aAAa,GAAG,OAAO,CAAC;QACxB,UAAU,CAAC,YAAY,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;QAEvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACnD,MAAM,SAAS,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;QAElD,yEAAyE;QACzE,mEAAmE;QACnE,qEAAqE;QACrE,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,SAAS,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC;QAC/E,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC;QAChD,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,SAAS,UAAU;QACjB,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnC,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,SAAS,gBAAgB;QACvB,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,YAAY,CAAC,WAAW,CAAC,CAAC;YAC1B,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED,SAAS,YAAY;QACnB,gBAAgB,EAAE,CAAC;QACnB,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,WAAW,GAAG,IAAI,CAAC;YACnB,UAAU,EAAE,CAAC;YACb,aAAa,GAAG,KAAK,CAAC;QACxB,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,4EAA4E;IAC5E,6CAA6C;IAC7C,4EAA4E;IAE5E,SAAS,WAAW,CAAC,CAAa;QAChC,MAAM,OAAO,GAAG,gBAAgB,CAAC,CAAC,CAAC,MAAc,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,OAAO,EAAE,CAAC;YACZ,gBAAgB,EAAE,CAAC;YACnB,aAAa,GAAG,IAAI,CAAC;YACrB,UAAU,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,SAAS,UAAU,CAAC,CAAa;QAC/B,MAAM,aAAa,GAAG,CAAC,CAAC,aAA4B,CAAC;QACrD,IAAI,aAAa,EAAE,CAAC;YAClB,2BAA2B;YAC3B,IAAI,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAAE,OAAO;YAC7C,mDAAmD;YACnD,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3D,IAAI,OAAO;oBAAE,OAAO;YACtB,CAAC;QACH,CAAC;QACD,YAAY,EAAE,CAAC;IACjB,CAAC;IAED,SAAS,kBAAkB;QACzB,gBAAgB,EAAE,CAAC;IACrB,CAAC;IAED,SAAS,kBAAkB,CAAC,CAAa;QACvC,MAAM,aAAa,GAAG,CAAC,CAAC,aAA4B,CAAC;QACrD,IAAI,aAAa,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACvD,MAAM,OAAO,GAAG,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3D,IAAI,OAAO;gBAAE,OAAO,CAAC,yBAAyB;QAChD,CAAC;QACD,YAAY,EAAE,CAAC;IACjB,CAAC;IAED,4EAA4E;IAC5E,uDAAuD;IACvD,4EAA4E;IAE5E,SAAS,WAAW;QAClB,UAAU,GAAG,IAAI,CAAC;QAClB,UAAU,EAAE,CAAC;IACf,CAAC;IAED,SAAS,SAAS;QAChB,UAAU,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,4EAA4E;IAC5E,0CAA0C;IAC1C,4EAA4E;IAE5E,IAAI,gBAAgB,GAAkB,IAAI,CAAC;IAC3C,IAAI,WAAW,GAAwB,IAAI,CAAC;IAC5C,IAAI,cAAc,GAAwB,IAAI,CAAC;IAE/C,SAAS,wBAAwB;QAC/B,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO;QAC9B,6BAA6B;QAC7B,IAAI,aAAa;YAAE,OAAO;QAC1B,IAAI,UAAU;YAAE,OAAO;QAEvB,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QAEtC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,KAAK,CAAC,EAAE,KAAK,gBAAgB;gBAAE,OAAO;YAE1C,gBAAgB,GAAG,KAAK,CAAC,EAAE,CAAC;YAE5B,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC,OAAO;gBAAE,OAAO,CAAC,mBAAmB;YAEzC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;YAC7B,UAAU,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAED,SAAS,uBAAuB;QAC9B,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,CAAC,oBAAoB;QAChD,KAAK,GAAG,qBAAqB,CAAC,GAAG,EAAE;YACjC,KAAK,GAAG,IAAI,CAAC;YACb,wBAAwB,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,4EAA4E;IAC5E,mBAAmB;IACnB,4EAA4E;IAE5E,SAAS,cAAc,CAAC,CAAa;QACnC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,wBAAwB;IAC9C,CAAC;IAED,SAAS,UAAU;QACjB,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE,OAAO;QAC9B,IAAI,CAAC,aAAa;YAAE,OAAO;QAE3B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;QAClC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC;QAC7D,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,UAAU,GAAG,mBAAmB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;QAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAE1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;YACnB,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE,WAAW;YACnB,UAAU;SACX,CAAC,CAAC;QAEH,gEAAgE;QAChE,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;IACtC,CAAC;IAED,4CAA4C;IAC5C,SAAS,qBAAqB,CAAC,CAAa;QAC1C,CAAC,CAAC,cAAc,EAAE,CAAC;IACrB,CAAC;IAED,4EAA4E;IAC5E,eAAe;IACf,4EAA4E;IAE5E,SAAS,MAAM;QACb,gBAAgB,EAAE,CAAC;QACnB,UAAU,EAAE,CAAC;QACb,aAAa,GAAG,KAAK,CAAC;QACtB,gBAAgB,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,4EAA4E;IAC5E,YAAY;IACZ,4EAA4E;IAE5E,OAAO;QACL,MAAM;YACJ,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAEhB,wBAAwB;YACxB,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAEhC,kBAAkB;YAClB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACrD,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACnD,QAAQ,CAAC,gBAAgB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;YAC5D,QAAQ,CAAC,gBAAgB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;YAE5D,mBAAmB;YACnB,SAAS,CAAC,gBAAgB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;YACxD,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAChD,UAAU,CAAC,gBAAgB,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;YAEhE,uBAAuB;YACvB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACrD,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAEjD,OAAO;YACP,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAE3C,oCAAoC;YACpC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,uBAAuB,EAAE,CAAC,CAAC;YACpE,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,CAAC,uBAAuB,EAAE,CAAC,CAAC;YAEhF,eAAe;YACf,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAC5B,CAAC;QAED,MAAM;YACJ,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,QAAQ,GAAG,KAAK,CAAC;YAEjB,kBAAkB;YAClB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACtD,QAAQ,CAAC,mBAAmB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;YAC/D,QAAQ,CAAC,mBAAmB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;YAE/D,mBAAmB;YACnB,SAAS,CAAC,mBAAmB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;YAC3D,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACnD,UAAU,CAAC,mBAAmB,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;YAEnE,uBAAuB;YACvB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YAEpD,OAAO;YACP,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAE9C,oBAAoB;YACpB,WAAW,EAAE,EAAE,CAAC;YAChB,cAAc,EAAE,EAAE,CAAC;YACnB,WAAW,GAAG,IAAI,CAAC;YACnB,cAAc,GAAG,IAAI,CAAC;YAEtB,qBAAqB;YACrB,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,oBAAoB,CAAC,KAAK,CAAC,CAAC;gBAC5B,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;YAED,eAAe;YACf,gBAAgB,CAAC,MAAM,EAAE,CAAC;YAE1B,aAAa;YACb,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBACxB,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAC5C,CAAC;YAED,cAAc;YACd,gBAAgB,EAAE,CAAC;YACnB,aAAa,GAAG,IAAI,CAAC;YACrB,aAAa,GAAG,KAAK,CAAC;YACtB,UAAU,GAAG,KAAK,CAAC;YACnB,gBAAgB,GAAG,IAAI,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context menu — right-click menu with Cut/Copy/Paste/Select All.
|
|
3
|
+
*
|
|
4
|
+
* Shows a positioned menu on `contextmenu` events with keyboard navigation,
|
|
5
|
+
* viewport clamping, and ARIA roles. Items are configurable via
|
|
6
|
+
* `ContextMenuConfig` on {@link WebEditorConfig}.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { IEditorEngine } from '@rtif-sdk/engine';
|
|
11
|
+
import type { WebEditor, ContextMenuItem, ContextMenuHandle } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Get the default context menu items (Cut, Copy, Paste, Paste as Plain Text,
|
|
14
|
+
* separator, Select All).
|
|
15
|
+
*
|
|
16
|
+
* @returns An array of default context menu items
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const items = getDefaultItems();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function getDefaultItems(): ContextMenuItem[];
|
|
24
|
+
/**
|
|
25
|
+
* Dependencies for creating a context menu. Internal — not exported as a
|
|
26
|
+
* public type. The `createWebEditor` factory wires these from its own scope.
|
|
27
|
+
*/
|
|
28
|
+
interface ContextMenuDeps {
|
|
29
|
+
readonly editor: WebEditor;
|
|
30
|
+
readonly root: HTMLElement;
|
|
31
|
+
readonly engine: IEditorEngine;
|
|
32
|
+
readonly isReadOnly: () => boolean;
|
|
33
|
+
readonly items?: ReadonlyArray<ContextMenuItem>;
|
|
34
|
+
readonly additionalItems?: ReadonlyArray<ContextMenuItem>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a context menu attached to the editor root.
|
|
38
|
+
*
|
|
39
|
+
* Intercepts the `contextmenu` event, builds the menu DOM, and manages
|
|
40
|
+
* keyboard navigation plus outside-click dismissal.
|
|
41
|
+
*
|
|
42
|
+
* @param deps - Dependencies injected by the editor factory
|
|
43
|
+
* @returns A {@link ContextMenuHandle} for programmatic control and cleanup
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const handle = createContextMenu({ editor, root, engine, isReadOnly: () => false });
|
|
48
|
+
* // later:
|
|
49
|
+
* handle.dispose();
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function createContextMenu(deps: ContextMenuDeps): ContextMenuHandle;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=context-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.d.ts","sourceRoot":"","sources":["../src/context-menu.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAGf,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAcpB;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,IAAI,eAAe,EAAE,CA6DnD;AA0GD;;;GAGG;AACH,UAAU,eAAe;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAChD,QAAQ,CAAC,eAAe,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CAC3D;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,iBAAiB,CAyS1E"}
|