@openeditor/ui 0.0.28 → 0.0.30
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/README.md +46 -1
- package/dist/index.css +176 -14
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.js +348 -128
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,19 +1,178 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Menu } from '@base-ui/react/menu';
|
|
2
|
+
import { Toolbar } from '@base-ui/react/toolbar';
|
|
3
|
+
import { useOpenEditorThemeStyle, OpenEditorTableBubbleMenu, OpenEditorBubbleMenu, sortSlashMenuItems, getDefaultSlashMenuItems, useOpenEditorBlockInteraction, OpenEditorBlockDragHandle, useOpenEditorController, OpenEditorThemeProvider, OpenEditorContent } from '@openeditor/react';
|
|
2
4
|
export { OpenEditorContent, OpenEditorThemeProvider, createOpenEditorThemeStyle, openEditorThemeTokenNames, useOpenEditorController } from '@openeditor/react';
|
|
5
|
+
import { Pilcrow, List, ListOrdered, ListTodo, Quote, Code, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Bold, Italic, Underline, Strikethrough, Link, GripVertical, Rows3, BetweenHorizontalStart, BetweenHorizontalEnd, Trash2, Columns3, BetweenVerticalStart, BetweenVerticalEnd, PanelTop, PanelLeft, TableCellsSplit, TableCellsMerge, ChevronDown, ChevronRight, X, ArrowDown, ArrowUp, Upload, FileText, GitBranch, MessageSquare, Table, Columns2, Image, Minus, Type, Copy, CopyPlus } from 'lucide-react';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
7
|
export { OpenEditorEmojiPicker } from '@openeditor/emoji';
|
|
4
8
|
import { Button } from '@base-ui/react/button';
|
|
5
9
|
import { Dialog } from '@base-ui/react/dialog';
|
|
6
10
|
import { Input } from '@base-ui/react/input';
|
|
7
|
-
import { Menu } from '@base-ui/react/menu';
|
|
8
11
|
import { Popover } from '@base-ui/react/popover';
|
|
9
12
|
import { Toggle } from '@base-ui/react/toggle';
|
|
10
13
|
import { ToggleGroup } from '@base-ui/react/toggle-group';
|
|
11
|
-
import {
|
|
12
|
-
import { Pilcrow, List, ListOrdered, ListTodo, Quote, Code, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Bold, Italic, Underline, Strikethrough, Link, ChevronRight, GripVertical, ChevronDown, X, ArrowDown, ArrowUp, Upload, FileText, GitBranch, MessageSquare, Table, Columns2, Image, Minus, Type, Copy, CopyPlus, Trash2 } from 'lucide-react';
|
|
13
|
-
import { useState, useRef, useMemo, useEffect, Fragment as Fragment$1 } from 'react';
|
|
14
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
14
|
+
import { useState, useRef, useEffect, useId, useMemo, useCallback, Fragment as Fragment$1 } from 'react';
|
|
15
15
|
|
|
16
|
-
// src/
|
|
16
|
+
// src/table-menu.tsx
|
|
17
|
+
var runTableCommandOnMouseDown = (event, controller, command) => {
|
|
18
|
+
if (event.button !== 0) return;
|
|
19
|
+
event.preventDefault();
|
|
20
|
+
controller.table.run(command);
|
|
21
|
+
};
|
|
22
|
+
var runTableCommandOnKeyboardClick = (event, controller, command) => {
|
|
23
|
+
if (event.detail === 0) controller.table.run(command);
|
|
24
|
+
};
|
|
25
|
+
var TableActionMenu = ({
|
|
26
|
+
controller,
|
|
27
|
+
container,
|
|
28
|
+
label,
|
|
29
|
+
Icon,
|
|
30
|
+
actions
|
|
31
|
+
}) => {
|
|
32
|
+
const themeStyle = useOpenEditorThemeStyle();
|
|
33
|
+
return /* @__PURE__ */ jsxs(Menu.Root, { modal: false, children: [
|
|
34
|
+
/* @__PURE__ */ jsxs(
|
|
35
|
+
Menu.Trigger,
|
|
36
|
+
{
|
|
37
|
+
"aria-label": `${label} actions`,
|
|
38
|
+
className: "oe-table-toolbar-trigger",
|
|
39
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
40
|
+
type: "button",
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", size: 15, strokeWidth: 2 }),
|
|
43
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
44
|
+
/* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true", size: 12, strokeWidth: 2 })
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
),
|
|
48
|
+
/* @__PURE__ */ jsx(Menu.Portal, { container, children: /* @__PURE__ */ jsx(
|
|
49
|
+
Menu.Positioner,
|
|
50
|
+
{
|
|
51
|
+
align: "start",
|
|
52
|
+
collisionAvoidance: { side: "flip", align: "shift", fallbackAxisSide: "none" },
|
|
53
|
+
collisionPadding: 12,
|
|
54
|
+
positionMethod: "fixed",
|
|
55
|
+
side: "bottom",
|
|
56
|
+
sideOffset: 8,
|
|
57
|
+
children: /* @__PURE__ */ jsx(Menu.Popup, { "aria-label": `${label} actions`, className: "oe-table-action-menu", style: themeStyle, children: actions.map((action) => /* @__PURE__ */ jsxs(
|
|
58
|
+
Menu.Item,
|
|
59
|
+
{
|
|
60
|
+
className: "oe-table-action-item",
|
|
61
|
+
"data-danger": action.danger ? "" : void 0,
|
|
62
|
+
disabled: !controller.table.can(action.command),
|
|
63
|
+
onClick: (event) => runTableCommandOnKeyboardClick(event, controller, action.command),
|
|
64
|
+
onMouseDown: (event) => runTableCommandOnMouseDown(event, controller, action.command),
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx(action.Icon, { "aria-hidden": "true", size: 15, strokeWidth: 2 }),
|
|
67
|
+
/* @__PURE__ */ jsx("span", { children: action.label })
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
action.command
|
|
71
|
+
)) })
|
|
72
|
+
}
|
|
73
|
+
) })
|
|
74
|
+
] });
|
|
75
|
+
};
|
|
76
|
+
var TableToolbarButton = ({
|
|
77
|
+
active,
|
|
78
|
+
children,
|
|
79
|
+
controller,
|
|
80
|
+
command,
|
|
81
|
+
label,
|
|
82
|
+
danger
|
|
83
|
+
}) => /* @__PURE__ */ jsx(
|
|
84
|
+
Toolbar.Button,
|
|
85
|
+
{
|
|
86
|
+
"aria-label": label,
|
|
87
|
+
className: "oe-table-toolbar-button",
|
|
88
|
+
"data-active": active ? "" : void 0,
|
|
89
|
+
"data-danger": danger ? "" : void 0,
|
|
90
|
+
disabled: !controller.table.can(command),
|
|
91
|
+
onClick: (event) => runTableCommandOnKeyboardClick(event, controller, command),
|
|
92
|
+
onMouseDown: (event) => runTableCommandOnMouseDown(event, controller, command),
|
|
93
|
+
title: label,
|
|
94
|
+
type: "button",
|
|
95
|
+
children
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
var rowActions = [
|
|
99
|
+
{ command: "addRowBefore", label: "Insert row above", Icon: BetweenHorizontalStart },
|
|
100
|
+
{ command: "addRowAfter", label: "Insert row below", Icon: BetweenHorizontalEnd },
|
|
101
|
+
{ command: "deleteRow", label: "Delete row", Icon: Trash2, danger: true }
|
|
102
|
+
];
|
|
103
|
+
var columnActions = [
|
|
104
|
+
{ command: "addColumnBefore", label: "Insert column left", Icon: BetweenVerticalStart },
|
|
105
|
+
{ command: "addColumnAfter", label: "Insert column right", Icon: BetweenVerticalEnd },
|
|
106
|
+
{ command: "deleteColumn", label: "Delete column", Icon: Trash2, danger: true }
|
|
107
|
+
];
|
|
108
|
+
var TableToolbar = ({
|
|
109
|
+
controller,
|
|
110
|
+
container,
|
|
111
|
+
state
|
|
112
|
+
}) => /* @__PURE__ */ jsx("div", { onMouseDown: (event) => event.preventDefault(), children: /* @__PURE__ */ jsxs(Toolbar.Root, { "aria-label": "Table editing", className: "oe-table-toolbar", children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
TableActionMenu,
|
|
115
|
+
{
|
|
116
|
+
actions: rowActions,
|
|
117
|
+
container,
|
|
118
|
+
controller,
|
|
119
|
+
Icon: Rows3,
|
|
120
|
+
label: "Row"
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
TableActionMenu,
|
|
125
|
+
{
|
|
126
|
+
actions: columnActions,
|
|
127
|
+
container,
|
|
128
|
+
controller,
|
|
129
|
+
Icon: Columns3,
|
|
130
|
+
label: "Column"
|
|
131
|
+
}
|
|
132
|
+
),
|
|
133
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "oe-table-toolbar-separator" }),
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
TableToolbarButton,
|
|
136
|
+
{
|
|
137
|
+
active: state.headerRow,
|
|
138
|
+
command: "toggleHeaderRow",
|
|
139
|
+
controller,
|
|
140
|
+
label: state.headerRow ? "Remove header row" : "Make first row a header",
|
|
141
|
+
children: /* @__PURE__ */ jsx(PanelTop, { "aria-hidden": "true", size: 15, strokeWidth: 2 })
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
/* @__PURE__ */ jsx(
|
|
145
|
+
TableToolbarButton,
|
|
146
|
+
{
|
|
147
|
+
active: state.headerColumn,
|
|
148
|
+
command: "toggleHeaderColumn",
|
|
149
|
+
controller,
|
|
150
|
+
label: state.headerColumn ? "Remove header column" : "Make first column a header",
|
|
151
|
+
children: /* @__PURE__ */ jsx(PanelLeft, { "aria-hidden": "true", size: 15, strokeWidth: 2 })
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
state.canSplitCell ? /* @__PURE__ */ jsx(TableToolbarButton, { command: "splitCell", controller, label: "Split cell", children: /* @__PURE__ */ jsx(TableCellsSplit, { "aria-hidden": "true", size: 15, strokeWidth: 2 }) }) : /* @__PURE__ */ jsx(TableToolbarButton, { command: "mergeCells", controller, label: "Merge selected cells", children: /* @__PURE__ */ jsx(TableCellsMerge, { "aria-hidden": "true", size: 15, strokeWidth: 2 }) }),
|
|
155
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "oe-table-toolbar-separator" }),
|
|
156
|
+
/* @__PURE__ */ jsx(TableToolbarButton, { command: "deleteTable", controller, danger: true, label: "Delete table", children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true", size: 15, strokeWidth: 2 }) })
|
|
157
|
+
] }) });
|
|
158
|
+
var OpenEditorTableMenu = ({
|
|
159
|
+
controller,
|
|
160
|
+
className = "oe-table-menu",
|
|
161
|
+
container
|
|
162
|
+
}) => {
|
|
163
|
+
const themeStyle = useOpenEditorThemeStyle();
|
|
164
|
+
if (!controller.ready) return null;
|
|
165
|
+
return /* @__PURE__ */ jsx(
|
|
166
|
+
OpenEditorTableBubbleMenu,
|
|
167
|
+
{
|
|
168
|
+
className,
|
|
169
|
+
container,
|
|
170
|
+
controller,
|
|
171
|
+
style: themeStyle,
|
|
172
|
+
children: (state) => /* @__PURE__ */ jsx(TableToolbar, { container, controller, state })
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
};
|
|
17
176
|
var headingDefinitions = [
|
|
18
177
|
{ level: 1, Icon: Heading1 },
|
|
19
178
|
{ level: 2, Icon: Heading2 },
|
|
@@ -118,10 +277,10 @@ var pointRect = (left, top) => ({
|
|
|
118
277
|
height: 0
|
|
119
278
|
});
|
|
120
279
|
var getAnchorRect = (state) => state.anchorRect ?? pointRect(state.left, state.top);
|
|
121
|
-
var toVirtualAnchor = (state, contextElement) => ({
|
|
280
|
+
var toVirtualAnchor = (state, contextElement, resolveRect) => ({
|
|
122
281
|
contextElement: contextElement ?? void 0,
|
|
123
282
|
getBoundingClientRect: () => {
|
|
124
|
-
const rect = getAnchorRect(state);
|
|
283
|
+
const rect = resolveRect?.() ?? getAnchorRect(state);
|
|
125
284
|
return {
|
|
126
285
|
...rect,
|
|
127
286
|
x: rect.left,
|
|
@@ -341,20 +500,9 @@ var OpenEditorSelectionBubble = ({
|
|
|
341
500
|
container
|
|
342
501
|
}) => {
|
|
343
502
|
const themeStyle = useOpenEditorThemeStyle();
|
|
344
|
-
const { selectionBubbleState } = controller;
|
|
345
503
|
const rootElement = controller.getRootElement();
|
|
346
504
|
const [linkDialogOpen, setLinkDialogOpen] = useState(false);
|
|
347
|
-
const
|
|
348
|
-
if (selectionBubbleState) {
|
|
349
|
-
lastAnchorRef.current = selectionBubbleState;
|
|
350
|
-
}
|
|
351
|
-
const anchor = useMemo(
|
|
352
|
-
() => {
|
|
353
|
-
const anchorState = selectionBubbleState ?? lastAnchorRef.current;
|
|
354
|
-
return anchorState ? toVirtualAnchor(anchorState, rootElement) : null;
|
|
355
|
-
},
|
|
356
|
-
[rootElement, selectionBubbleState]
|
|
357
|
-
);
|
|
505
|
+
const toolbarRef = useRef(null);
|
|
358
506
|
const actions = controller.ready ? [
|
|
359
507
|
{
|
|
360
508
|
key: "bold",
|
|
@@ -392,45 +540,68 @@ var OpenEditorSelectionBubble = ({
|
|
|
392
540
|
run: () => controller.toggleInlineCode()
|
|
393
541
|
}
|
|
394
542
|
] : [];
|
|
395
|
-
|
|
396
|
-
return
|
|
397
|
-
|
|
543
|
+
useEffect(() => {
|
|
544
|
+
if (!rootElement) return;
|
|
545
|
+
const focusToolbar = (event) => {
|
|
546
|
+
if (!(event.altKey && event.key === "F10")) return;
|
|
547
|
+
const toolbar = toolbarRef.current;
|
|
548
|
+
const menu = toolbar?.parentElement?.parentElement;
|
|
549
|
+
if (!toolbar || !menu || getComputedStyle(menu).visibility === "hidden") return;
|
|
550
|
+
const firstControl = toolbarRef.current?.querySelector(
|
|
551
|
+
"button:not(:disabled), [href], [tabindex]:not([tabindex='-1'])"
|
|
552
|
+
);
|
|
553
|
+
if (!firstControl) return;
|
|
554
|
+
event.preventDefault();
|
|
555
|
+
firstControl.focus();
|
|
556
|
+
};
|
|
557
|
+
rootElement.addEventListener("keydown", focusToolbar, true);
|
|
558
|
+
return () => rootElement.removeEventListener("keydown", focusToolbar, true);
|
|
559
|
+
}, [rootElement]);
|
|
560
|
+
if (!controller.ready) return null;
|
|
398
561
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
399
|
-
/* @__PURE__ */ jsx(
|
|
400
|
-
|
|
562
|
+
/* @__PURE__ */ jsx(
|
|
563
|
+
OpenEditorBubbleMenu,
|
|
401
564
|
{
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
sideOffset: 10,
|
|
407
|
-
collisionPadding: 12,
|
|
408
|
-
collisionAvoidance: { side: "flip", align: "shift", fallbackAxisSide: "none" },
|
|
565
|
+
className,
|
|
566
|
+
container,
|
|
567
|
+
controller,
|
|
568
|
+
style: themeStyle,
|
|
409
569
|
children: /* @__PURE__ */ jsx(
|
|
410
|
-
|
|
570
|
+
"div",
|
|
411
571
|
{
|
|
412
|
-
|
|
413
|
-
|
|
572
|
+
onKeyDown: (event) => {
|
|
573
|
+
if (event.key !== "Escape") return;
|
|
574
|
+
event.preventDefault();
|
|
575
|
+
controller.focus();
|
|
576
|
+
},
|
|
414
577
|
onMouseDown: (event) => event.preventDefault(),
|
|
415
|
-
children: /* @__PURE__ */ jsxs(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
578
|
+
children: /* @__PURE__ */ jsxs(
|
|
579
|
+
Toolbar.Root,
|
|
580
|
+
{
|
|
581
|
+
className: "oe-selection-toolbar",
|
|
582
|
+
"aria-label": "Selection formatting",
|
|
583
|
+
ref: toolbarRef,
|
|
584
|
+
children: [
|
|
585
|
+
/* @__PURE__ */ jsx(SelectionBlockTransformMenu, { controller, container }),
|
|
586
|
+
actions.map((action) => /* @__PURE__ */ jsx(SelectionButton, { action }, action.key)),
|
|
587
|
+
/* @__PURE__ */ jsx(
|
|
588
|
+
Toolbar.Button,
|
|
589
|
+
{
|
|
590
|
+
type: "button",
|
|
591
|
+
"aria-label": "Link",
|
|
592
|
+
className: "oe-toolbar-button",
|
|
593
|
+
"data-active": controller.isActive("link") ? "" : void 0,
|
|
594
|
+
onClick: () => setLinkDialogOpen(true),
|
|
595
|
+
children: /* @__PURE__ */ jsx(Link, { "aria-hidden": "true", className: "oe-toolbar-icon", size: 15, strokeWidth: 2 })
|
|
596
|
+
}
|
|
597
|
+
)
|
|
598
|
+
]
|
|
599
|
+
}
|
|
600
|
+
)
|
|
430
601
|
}
|
|
431
602
|
)
|
|
432
603
|
}
|
|
433
|
-
)
|
|
604
|
+
),
|
|
434
605
|
/* @__PURE__ */ jsx(
|
|
435
606
|
OpenEditorLinkDialog,
|
|
436
607
|
{
|
|
@@ -450,103 +621,137 @@ var OpenEditorSlashMenu = ({
|
|
|
450
621
|
const themeStyle = useOpenEditorThemeStyle();
|
|
451
622
|
const slashMenuItems = sortSlashMenuItems(items ?? getDefaultSlashMenuItems(controller));
|
|
452
623
|
const slashState = controller.slashState;
|
|
453
|
-
const [
|
|
624
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
625
|
+
const selectedIndexRef = useRef(0);
|
|
626
|
+
const menuId = useId();
|
|
627
|
+
const menuRef = useRef(null);
|
|
454
628
|
const anchor = useMemo(
|
|
455
629
|
() => slashState ? toVirtualAnchor(
|
|
456
630
|
slashState,
|
|
457
|
-
controller.getRootElement()
|
|
631
|
+
controller.getRootElement(),
|
|
632
|
+
() => controller.getPositionRect(slashState.to)
|
|
458
633
|
) : null,
|
|
459
634
|
[controller, slashState]
|
|
460
635
|
);
|
|
461
|
-
|
|
462
|
-
if (!slashState) {
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
const matchingItems = slashMenuItems.filter((item) => {
|
|
636
|
+
const matchingItems = slashState ? slashMenuItems.filter((item) => {
|
|
466
637
|
const haystack = `${item.label} ${item.group} ${item.keywords?.join(" ") ?? ""}`.toLowerCase();
|
|
467
638
|
return haystack.includes(slashState.query.toLowerCase());
|
|
468
|
-
});
|
|
469
|
-
|
|
639
|
+
}) : [];
|
|
640
|
+
selectedIndexRef.current = selectedIndex;
|
|
641
|
+
useEffect(() => {
|
|
642
|
+
selectedIndexRef.current = 0;
|
|
643
|
+
setSelectedIndex(0);
|
|
644
|
+
}, [slashState?.from, slashState?.query]);
|
|
645
|
+
useEffect(() => {
|
|
646
|
+
if (selectedIndex < matchingItems.length) return;
|
|
647
|
+
setSelectedIndex(Math.max(0, matchingItems.length - 1));
|
|
648
|
+
}, [matchingItems.length, selectedIndex]);
|
|
649
|
+
useEffect(() => {
|
|
650
|
+
const editorElement = controller.getRootElement();
|
|
651
|
+
if (!slashState || !editorElement) return;
|
|
652
|
+
const previous = {
|
|
653
|
+
controls: editorElement.getAttribute("aria-controls"),
|
|
654
|
+
expanded: editorElement.getAttribute("aria-expanded"),
|
|
655
|
+
activeDescendant: editorElement.getAttribute("aria-activedescendant")
|
|
656
|
+
};
|
|
657
|
+
const selectedId = matchingItems[selectedIndex] ? `${menuId}-option-${selectedIndex}` : null;
|
|
658
|
+
editorElement.setAttribute("aria-controls", menuId);
|
|
659
|
+
editorElement.setAttribute("aria-expanded", "true");
|
|
660
|
+
if (selectedId) editorElement.setAttribute("aria-activedescendant", selectedId);
|
|
661
|
+
else editorElement.removeAttribute("aria-activedescendant");
|
|
662
|
+
const handleKeyDown = (event) => {
|
|
663
|
+
if (event.isComposing) return false;
|
|
664
|
+
let nextIndex = null;
|
|
665
|
+
const currentIndex = selectedIndexRef.current;
|
|
666
|
+
if (event.key === "ArrowDown") nextIndex = (currentIndex + 1) % Math.max(1, matchingItems.length);
|
|
667
|
+
if (event.key === "ArrowUp") nextIndex = (currentIndex - 1 + Math.max(1, matchingItems.length)) % Math.max(1, matchingItems.length);
|
|
668
|
+
if (event.key === "Home" || event.key === "PageUp") nextIndex = 0;
|
|
669
|
+
if (event.key === "End" || event.key === "PageDown") nextIndex = Math.max(0, matchingItems.length - 1);
|
|
670
|
+
if (nextIndex !== null) {
|
|
671
|
+
event.preventDefault();
|
|
672
|
+
selectedIndexRef.current = nextIndex;
|
|
673
|
+
setSelectedIndex(nextIndex);
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
if (event.key === "Enter") {
|
|
677
|
+
const item = matchingItems[selectedIndexRef.current];
|
|
678
|
+
if (!item) return false;
|
|
679
|
+
event.preventDefault();
|
|
680
|
+
event.stopPropagation();
|
|
681
|
+
item.execute({ controller, range: { from: slashState.from, to: slashState.to } });
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
return false;
|
|
685
|
+
};
|
|
686
|
+
const unregisterKeyboardHandler = controller.registerSlashMenuKeyboardHandler(handleKeyDown);
|
|
687
|
+
return () => {
|
|
688
|
+
unregisterKeyboardHandler();
|
|
689
|
+
for (const [attribute, value] of [
|
|
690
|
+
["aria-controls", previous.controls],
|
|
691
|
+
["aria-expanded", previous.expanded],
|
|
692
|
+
["aria-activedescendant", previous.activeDescendant]
|
|
693
|
+
]) {
|
|
694
|
+
if (value === null) editorElement.removeAttribute(attribute);
|
|
695
|
+
else editorElement.setAttribute(attribute, value);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
}, [controller, matchingItems, menuId, selectedIndex, slashState]);
|
|
699
|
+
useEffect(() => {
|
|
700
|
+
menuRef.current?.querySelector("[data-highlighted]")?.scrollIntoView({ block: "nearest" });
|
|
701
|
+
}, [selectedIndex]);
|
|
702
|
+
if (!slashState) return null;
|
|
470
703
|
return /* @__PURE__ */ jsx(Popover.Root, { open: true, modal: false, children: /* @__PURE__ */ jsx(Popover.Portal, { container, children: /* @__PURE__ */ jsx(
|
|
471
704
|
Popover.Positioner,
|
|
472
705
|
{
|
|
473
706
|
anchor,
|
|
707
|
+
className: "oe-anchored-overlay-positioner",
|
|
474
708
|
positionMethod: "fixed",
|
|
475
709
|
side: "bottom",
|
|
476
710
|
align: "start",
|
|
477
711
|
sideOffset: 8,
|
|
478
712
|
collisionPadding: 12,
|
|
479
713
|
collisionAvoidance: { side: "flip", align: "shift", fallbackAxisSide: "none" },
|
|
480
|
-
children: /* @__PURE__ */
|
|
714
|
+
children: /* @__PURE__ */ jsx(
|
|
481
715
|
Popover.Popup,
|
|
482
716
|
{
|
|
483
717
|
className: "oe-cascade-menu",
|
|
484
|
-
style: themeStyle,
|
|
485
718
|
finalFocus: false,
|
|
719
|
+
style: themeStyle,
|
|
486
720
|
initialFocus: false,
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
721
|
+
children: /* @__PURE__ */ jsx(
|
|
722
|
+
"div",
|
|
723
|
+
{
|
|
724
|
+
"aria-label": "Insert block",
|
|
725
|
+
className: `${className} oe-cascade-panel`,
|
|
726
|
+
id: menuId,
|
|
727
|
+
ref: menuRef,
|
|
728
|
+
role: "listbox",
|
|
729
|
+
children: /* @__PURE__ */ jsx("div", { className: "oe-slash-menu-scroll", children: matchingItems.map((item, index) => {
|
|
730
|
+
const Icon = getSlashMenuIcon(item);
|
|
492
731
|
return /* @__PURE__ */ jsxs(
|
|
493
732
|
"button",
|
|
494
733
|
{
|
|
734
|
+
"aria-selected": index === selectedIndex,
|
|
495
735
|
type: "button",
|
|
496
736
|
className: "oe-slash-menu-item",
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
onMouseEnter: () =>
|
|
737
|
+
"data-highlighted": index === selectedIndex ? "" : void 0,
|
|
738
|
+
id: `${menuId}-option-${index}`,
|
|
739
|
+
onMouseEnter: () => setSelectedIndex(index),
|
|
500
740
|
onMouseDown: (event) => event.preventDefault(),
|
|
741
|
+
onClick: () => {
|
|
742
|
+
item.execute({ controller, range: { from: slashState.from, to: slashState.to } });
|
|
743
|
+
},
|
|
744
|
+
role: "option",
|
|
501
745
|
children: [
|
|
502
|
-
/* @__PURE__ */ jsx(
|
|
503
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
504
|
-
/* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "oe-submenu-chevron", size: 13, strokeWidth: 2 })
|
|
746
|
+
/* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "oe-slash-menu-icon", size: 15, strokeWidth: 2 }),
|
|
747
|
+
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
505
748
|
]
|
|
506
749
|
},
|
|
507
|
-
|
|
750
|
+
item.key
|
|
508
751
|
);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
"button",
|
|
513
|
-
{
|
|
514
|
-
type: "button",
|
|
515
|
-
className: "oe-slash-menu-item",
|
|
516
|
-
onMouseEnter: () => setHeadingPanelOpen(false),
|
|
517
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
518
|
-
onClick: () => {
|
|
519
|
-
item.execute({ controller, range: { from: slashState.from, to: slashState.to } });
|
|
520
|
-
},
|
|
521
|
-
children: [
|
|
522
|
-
/* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "oe-slash-menu-icon", size: 15, strokeWidth: 2 }),
|
|
523
|
-
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
524
|
-
]
|
|
525
|
-
},
|
|
526
|
-
item.key
|
|
527
|
-
);
|
|
528
|
-
}) }) }),
|
|
529
|
-
headingPanelOpen ? /* @__PURE__ */ jsx("div", { className: "oe-slash-menu oe-slash-submenu oe-cascade-panel", children: matchingItems.filter((item) => isHeadingKey(item.key)).map((headingItem) => {
|
|
530
|
-
const HeadingIcon = getSlashMenuIcon(headingItem);
|
|
531
|
-
return /* @__PURE__ */ jsxs(
|
|
532
|
-
"button",
|
|
533
|
-
{
|
|
534
|
-
type: "button",
|
|
535
|
-
className: "oe-slash-menu-item",
|
|
536
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
537
|
-
onClick: () => {
|
|
538
|
-
headingItem.execute({ controller, range: { from: slashState.from, to: slashState.to } });
|
|
539
|
-
},
|
|
540
|
-
role: "menuitem",
|
|
541
|
-
children: [
|
|
542
|
-
/* @__PURE__ */ jsx(HeadingIcon, { "aria-hidden": true, className: "oe-slash-menu-icon", size: 15, strokeWidth: 2 }),
|
|
543
|
-
/* @__PURE__ */ jsx("span", { children: headingItem.label })
|
|
544
|
-
]
|
|
545
|
-
},
|
|
546
|
-
headingItem.key
|
|
547
|
-
);
|
|
548
|
-
}) }) : null
|
|
549
|
-
]
|
|
752
|
+
}) })
|
|
753
|
+
}
|
|
754
|
+
)
|
|
550
755
|
}
|
|
551
756
|
)
|
|
552
757
|
}
|
|
@@ -610,8 +815,28 @@ var OpenEditorBlockMenu = ({
|
|
|
610
815
|
const [open, setOpen] = useState(false);
|
|
611
816
|
const handleElementRef = useRef(null);
|
|
612
817
|
const lastBlockRef = useRef(null);
|
|
818
|
+
const controllerRef = useRef(controller);
|
|
819
|
+
controllerRef.current = controller;
|
|
613
820
|
if (block) lastBlockRef.current = block;
|
|
614
821
|
const activeBlock = block ?? (open ? lastBlockRef.current : null);
|
|
822
|
+
const setMenuOpen = useCallback((nextOpen) => {
|
|
823
|
+
const selected = lastBlockRef.current;
|
|
824
|
+
if (nextOpen) {
|
|
825
|
+
if (!selected || !controllerRef.current.selectBlock(selected)) {
|
|
826
|
+
setOpen(false);
|
|
827
|
+
controllerRef.current.setBlockHandleLocked(false);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
controllerRef.current.setBlockHandleLocked(true);
|
|
831
|
+
setOpen(true);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
setOpen(false);
|
|
835
|
+
controllerRef.current.setBlockHandleLocked(false);
|
|
836
|
+
}, []);
|
|
837
|
+
useEffect(() => () => {
|
|
838
|
+
controllerRef.current.setBlockHandleLocked(false);
|
|
839
|
+
}, []);
|
|
615
840
|
if (!controller.editable) return null;
|
|
616
841
|
const handle = /* @__PURE__ */ jsx(
|
|
617
842
|
OpenEditorBlockDragHandle,
|
|
@@ -622,25 +847,18 @@ var OpenEditorBlockMenu = ({
|
|
|
622
847
|
elementRef: handleElementRef,
|
|
623
848
|
expanded: open,
|
|
624
849
|
onActivate: () => {
|
|
625
|
-
|
|
626
|
-
setOpen(nextOpen);
|
|
627
|
-
controller.setBlockHandleLocked(nextOpen);
|
|
628
|
-
if (nextOpen && activeBlock) controller.selectBlock(activeBlock);
|
|
850
|
+
setMenuOpen(!open);
|
|
629
851
|
},
|
|
630
852
|
onDraggingChange: (dragging) => {
|
|
631
|
-
if (dragging)
|
|
853
|
+
if (dragging) setMenuOpen(false);
|
|
632
854
|
},
|
|
633
855
|
children: activeBlock ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cx("oe-block-handle", className), children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true", size: 16, strokeWidth: 2 }) }) : null
|
|
634
856
|
}
|
|
635
857
|
);
|
|
636
858
|
const actions = activeBlock ? [...builtInBlockActions(controller, activeBlock), ...controller.blockActions] : [];
|
|
637
|
-
return /* @__PURE__ */ jsxs(Menu.Root, { modal: false, open, onOpenChange:
|
|
638
|
-
setOpen(nextOpen);
|
|
639
|
-
controller.setBlockHandleLocked(nextOpen);
|
|
640
|
-
if (nextOpen && activeBlock) controller.selectBlock(activeBlock);
|
|
641
|
-
}, children: [
|
|
859
|
+
return /* @__PURE__ */ jsxs(Menu.Root, { modal: false, open, onOpenChange: setMenuOpen, children: [
|
|
642
860
|
handle,
|
|
643
|
-
activeBlock ? /* @__PURE__ */ jsx(Menu.Portal, { container, children: /* @__PURE__ */ jsx(
|
|
861
|
+
open && activeBlock ? /* @__PURE__ */ jsx(Menu.Portal, { container, children: /* @__PURE__ */ jsx(
|
|
644
862
|
Menu.Positioner,
|
|
645
863
|
{
|
|
646
864
|
align: "start",
|
|
@@ -669,6 +887,7 @@ var OpenEditorBlockMenu = ({
|
|
|
669
887
|
"data-danger": action.group === "danger" ? "" : void 0,
|
|
670
888
|
disabled: action.disabled?.(context),
|
|
671
889
|
onClick: () => {
|
|
890
|
+
setMenuOpen(false);
|
|
672
891
|
void action.run(context);
|
|
673
892
|
},
|
|
674
893
|
children: [
|
|
@@ -697,11 +916,12 @@ var OpenEditor = ({
|
|
|
697
916
|
/* @__PURE__ */ jsx(OpenEditorContent, { controller, className: contentClassName }),
|
|
698
917
|
/* @__PURE__ */ jsx(OpenEditorBlockMenu, { controller, container: overlayContainer }),
|
|
699
918
|
/* @__PURE__ */ jsx(OpenEditorSelectionBubble, { controller, container: overlayContainer }),
|
|
919
|
+
/* @__PURE__ */ jsx(OpenEditorTableMenu, { controller, container: overlayContainer }),
|
|
700
920
|
/* @__PURE__ */ jsx(OpenEditorSlashMenu, { controller, container: overlayContainer })
|
|
701
921
|
] });
|
|
702
922
|
return theme ? /* @__PURE__ */ jsx(OpenEditorThemeProvider, { theme, children: editor }) : editor;
|
|
703
923
|
};
|
|
704
924
|
|
|
705
|
-
export { OpenEditor, OpenEditorBlockMenu, OpenEditorButton, OpenEditorInput, OpenEditorSelectionBubble, OpenEditorSlashMenu, OpenEditorToggle, OpenEditorToggleGroup };
|
|
925
|
+
export { OpenEditor, OpenEditorBlockMenu, OpenEditorButton, OpenEditorInput, OpenEditorSelectionBubble, OpenEditorSlashMenu, OpenEditorTableMenu, OpenEditorToggle, OpenEditorToggleGroup };
|
|
706
926
|
//# sourceMappingURL=index.js.map
|
|
707
927
|
//# sourceMappingURL=index.js.map
|