@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.
Files changed (50) hide show
  1. package/dist/block-drag-handler.d.ts +26 -0
  2. package/dist/block-drag-handler.d.ts.map +1 -1
  3. package/dist/block-drag-handler.js +33 -23
  4. package/dist/block-drag-handler.js.map +1 -1
  5. package/dist/block-gutter.d.ts +81 -0
  6. package/dist/block-gutter.d.ts.map +1 -0
  7. package/dist/block-gutter.js +331 -0
  8. package/dist/block-gutter.js.map +1 -0
  9. package/dist/context-menu.d.ts +54 -0
  10. package/dist/context-menu.d.ts.map +1 -0
  11. package/dist/context-menu.js +470 -0
  12. package/dist/context-menu.js.map +1 -0
  13. package/dist/drop-indicator.d.ts.map +1 -1
  14. package/dist/drop-indicator.js +8 -34
  15. package/dist/drop-indicator.js.map +1 -1
  16. package/dist/editor.d.ts +1 -1
  17. package/dist/editor.d.ts.map +1 -1
  18. package/dist/editor.js +153 -12
  19. package/dist/editor.js.map +1 -1
  20. package/dist/floating-toolbar.d.ts.map +1 -1
  21. package/dist/floating-toolbar.js +4 -7
  22. package/dist/floating-toolbar.js.map +1 -1
  23. package/dist/index.d.ts +4 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +6 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/link-popover.d.ts.map +1 -1
  28. package/dist/link-popover.js +2 -43
  29. package/dist/link-popover.js.map +1 -1
  30. package/dist/renderer.d.ts.map +1 -1
  31. package/dist/renderer.js +27 -5
  32. package/dist/renderer.js.map +1 -1
  33. package/dist/selection-sync.d.ts.map +1 -1
  34. package/dist/selection-sync.js +20 -3
  35. package/dist/selection-sync.js.map +1 -1
  36. package/dist/types.d.ts +208 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/package.json +8 -4
  39. package/styles/all.css +21 -0
  40. package/styles/base.css +33 -0
  41. package/styles/block-gutter.css +76 -0
  42. package/styles/blocks.css +199 -0
  43. package/styles/context-menu.css +58 -0
  44. package/styles/drop-indicator.css +37 -0
  45. package/styles/floating-toolbar.css +51 -0
  46. package/styles/link-popover.css +64 -0
  47. package/styles/marks.css +27 -0
  48. package/styles/mention.css +17 -0
  49. package/styles/pickers.css +317 -0
  50. 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"}