@openeditor/react 0.0.23 → 0.0.24
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 +51 -5
- package/dist/index.d.ts +22 -1
- package/dist/index.js +29 -4
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Pass `attachmentRuntime` to `useOpenEditorController` for editable attachments a
|
|
|
9
9
|
- `useOpenEditorController` for editor state, commands, document exports, and selection state
|
|
10
10
|
- `OpenEditorContent` for the editable Tiptap-backed content surface
|
|
11
11
|
- `OpenEditorViewer` for read-only React rendering
|
|
12
|
+
- `getDefaultBlockPickerItems` for host-owned block rails, pickers, and command palettes
|
|
12
13
|
- `getDefaultSlashMenuItems` for UI packages that want the built-in insert actions
|
|
13
14
|
- position-based block targeting and transaction-backed copy, duplicate, move, and delete commands
|
|
14
15
|
- `defineOpenEditorReactNode` for consumer-owned React blocks
|
|
@@ -34,6 +35,49 @@ Pass `blockActions` to contribute product-specific actions. The optional
|
|
|
34
35
|
Copy, Duplicate, and Delete. Clipboard copies use a versioned OpenEditor block
|
|
35
36
|
envelope so blocks can move between independent editor instances and documents.
|
|
36
37
|
|
|
38
|
+
## Host-owned block pickers
|
|
39
|
+
|
|
40
|
+
Use `getDefaultBlockPickerItems` when blocks need to be discoverable outside the
|
|
41
|
+
slash menu. The catalog contains built-in insert presets and registered custom
|
|
42
|
+
blocks, but deliberately excludes slash-only actions such as moving a block or
|
|
43
|
+
converting a whole document. Use `sortBlockPickerItems` when merging additional
|
|
44
|
+
host-owned entries into the catalog.
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import {
|
|
48
|
+
getDefaultBlockPickerItems,
|
|
49
|
+
OpenEditorContent,
|
|
50
|
+
useOpenEditorController,
|
|
51
|
+
} from "@openeditor/react";
|
|
52
|
+
|
|
53
|
+
export function EditorWithBlockRail() {
|
|
54
|
+
const controller = useOpenEditorController({ extensions });
|
|
55
|
+
const items = getDefaultBlockPickerItems(controller);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
<aside aria-label="Blocks">
|
|
60
|
+
{items.map((item) => (
|
|
61
|
+
<button
|
|
62
|
+
key={item.key}
|
|
63
|
+
onMouseDown={(event) => event.preventDefault()}
|
|
64
|
+
onClick={item.insert}
|
|
65
|
+
type="button"
|
|
66
|
+
>
|
|
67
|
+
{item.label}
|
|
68
|
+
</button>
|
|
69
|
+
))}
|
|
70
|
+
</aside>
|
|
71
|
+
<OpenEditorContent controller={controller} />
|
|
72
|
+
</>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`item.insert()` restores focus and inserts at the controller's current editor
|
|
78
|
+
selection. Preventing the button's mouse-down default keeps the caret visibly
|
|
79
|
+
anchored while the user moves from the editor to a host-owned picker.
|
|
80
|
+
|
|
37
81
|
The built-in web catalog includes editable Toggle Lists, rich-content Callouts,
|
|
38
82
|
and Mermaid-powered Diagrams. Diagrams use `beautiful-mermaid` for synchronous,
|
|
39
83
|
themeable SVG rendering and retain their canonical Mermaid source in the document.
|
|
@@ -114,7 +158,7 @@ const productCard = defineOpenEditorReactNode({
|
|
|
114
158
|
],
|
|
115
159
|
},
|
|
116
160
|
component: ProductCardNode,
|
|
117
|
-
|
|
161
|
+
insertMenu: {
|
|
118
162
|
icon: PackageOpen,
|
|
119
163
|
keywords: ["product", "commerce", "card"],
|
|
120
164
|
order: 250,
|
|
@@ -143,13 +187,15 @@ Pass the same extension array to `OpenEditorViewer`. The controller automaticall
|
|
|
143
187
|
uses registered exporters for `controller.exports` and registered blocks appear
|
|
144
188
|
in `getDefaultSlashMenuItems`, which powers `@openeditor/ui`.
|
|
145
189
|
|
|
146
|
-
|
|
190
|
+
Insert-menu entries accept an optional React `icon` component and numeric `order`.
|
|
147
191
|
OpenEditor assigns built-in entries orders in increments of 100, so consumer
|
|
148
192
|
blocks can be placed between them (for example, `order: 250` appears between
|
|
149
193
|
Heading 1 and Heading 2). Entries with the same order retain their declaration
|
|
150
|
-
order, and entries without an order appear after ordered entries.
|
|
151
|
-
|
|
152
|
-
|
|
194
|
+
order, and entries without an order appear after ordered entries. This metadata
|
|
195
|
+
is shared by slash menus and `getDefaultBlockPickerItems`; use `insertMenu: false`
|
|
196
|
+
to keep a block out of both discovery surfaces. The legacy `slashMenu` extension
|
|
197
|
+
field remains supported. The same fields are available on direct
|
|
198
|
+
`slashMenuItems`; a slash menu's explicit `items` prop is also sorted by this rule.
|
|
153
199
|
|
|
154
200
|
Block `name` is the stable public identifier. Namespace consumer blocks to avoid
|
|
155
201
|
collisions. `nodeType` is the serialized ProseMirror node type and defaults to
|
package/dist/index.d.ts
CHANGED
|
@@ -161,6 +161,22 @@ type OpenEditorSlashMenuItem = {
|
|
|
161
161
|
range: InsertRange;
|
|
162
162
|
}) => boolean;
|
|
163
163
|
};
|
|
164
|
+
/**
|
|
165
|
+
* An insertable block exposed to host-owned pickers and command palettes.
|
|
166
|
+
*
|
|
167
|
+
* Unlike `OpenEditorSlashMenuItem`, this contract contains only block insertion
|
|
168
|
+
* and is not coupled to a slash query range. Calling `insert` restores editor
|
|
169
|
+
* focus and inserts at the controller's current selection.
|
|
170
|
+
*/
|
|
171
|
+
type OpenEditorBlockPickerItem = {
|
|
172
|
+
key: string;
|
|
173
|
+
label: string;
|
|
174
|
+
group: string;
|
|
175
|
+
icon?: OpenEditorSlashMenuIcon;
|
|
176
|
+
keywords?: readonly string[];
|
|
177
|
+
order?: number;
|
|
178
|
+
insert: () => boolean;
|
|
179
|
+
};
|
|
164
180
|
type OpenEditorViewerRenderer = (context: {
|
|
165
181
|
node: ProseMirrorNode;
|
|
166
182
|
children: ReactNode;
|
|
@@ -180,6 +196,9 @@ type OpenEditorExtensionMenu = {
|
|
|
180
196
|
type OpenEditorReactExtension = {
|
|
181
197
|
block: BlockSpec;
|
|
182
198
|
tiptapExtensions: readonly AnyExtension[];
|
|
199
|
+
/** Discovery metadata shared by slash menus and host-owned block pickers. */
|
|
200
|
+
insertMenu?: false | OpenEditorExtensionMenu;
|
|
201
|
+
/** @deprecated Use `insertMenu`. */
|
|
183
202
|
slashMenu?: false | OpenEditorExtensionMenu;
|
|
184
203
|
viewer: OpenEditorViewerRenderer;
|
|
185
204
|
exporters?: OpenEditorExporters;
|
|
@@ -209,9 +228,11 @@ declare module "@tiptap/core" {
|
|
|
209
228
|
declare const formatAttachmentSize: (size: number | null) => string;
|
|
210
229
|
declare const useOpenEditorController: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, pageRuntime, attachmentRuntime, slashMenuItems, extensions, blockActions, }?: OpenEditorReactProps) => OpenEditorController;
|
|
211
230
|
declare const sortSlashMenuItems: (items: readonly OpenEditorSlashMenuItem[]) => OpenEditorSlashMenuItem[];
|
|
231
|
+
declare const sortBlockPickerItems: (items: readonly OpenEditorBlockPickerItem[]) => OpenEditorBlockPickerItem[];
|
|
232
|
+
declare const getDefaultBlockPickerItems: (controller: OpenEditorController) => OpenEditorBlockPickerItem[];
|
|
212
233
|
declare const getDefaultSlashMenuItems: (controller: OpenEditorController) => OpenEditorSlashMenuItem[];
|
|
213
234
|
declare const OpenEditorContent: ({ controller, className, }: OpenEditorContentProps) => react.JSX.Element;
|
|
214
235
|
declare const OpenEditorViewer: ({ document, className, renderers, extensions, pageRuntime, attachmentRuntime, }: OpenEditorViewerProps) => react.JSX.Element;
|
|
215
236
|
declare const useOpenEditor: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, pageRuntime, attachmentRuntime, slashMenuItems, extensions, blockActions, }?: OpenEditorReactProps) => OpenEditorController;
|
|
216
237
|
|
|
217
|
-
export { type InsertRange, type OpenEditorBlockAction, type OpenEditorBlockActionContext, type OpenEditorBlockTarget, OpenEditorContent, type OpenEditorContentProps, type OpenEditorController, type OpenEditorExtensionMenu, type OpenEditorOverlayRect, type OpenEditorPageRuntime, type OpenEditorPageSnapshot, type OpenEditorReactConfig, type OpenEditorReactExtension, type OpenEditorReactNodeExtension, type OpenEditorReactProps, type OpenEditorSlashMenuIcon, type OpenEditorSlashMenuIconProps, type OpenEditorSlashMenuItem, type OpenEditorTheme, OpenEditorThemeProvider, type OpenEditorThemeStyle, type OpenEditorThemeToken, OpenEditorViewer, type OpenEditorViewerProps, type OpenEditorViewerRenderer, type SelectionBubbleState, type SlashState, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultSlashMenuItems, openEditorThemeTokenNames, sortSlashMenuItems, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
|
238
|
+
export { type InsertRange, type OpenEditorBlockAction, type OpenEditorBlockActionContext, type OpenEditorBlockPickerItem, type OpenEditorBlockTarget, OpenEditorContent, type OpenEditorContentProps, type OpenEditorController, type OpenEditorExtensionMenu, type OpenEditorOverlayRect, type OpenEditorPageRuntime, type OpenEditorPageSnapshot, type OpenEditorReactConfig, type OpenEditorReactExtension, type OpenEditorReactNodeExtension, type OpenEditorReactProps, type OpenEditorSlashMenuIcon, type OpenEditorSlashMenuIconProps, type OpenEditorSlashMenuItem, type OpenEditorTheme, OpenEditorThemeProvider, type OpenEditorThemeStyle, type OpenEditorThemeToken, OpenEditorViewer, type OpenEditorViewerProps, type OpenEditorViewerRenderer, type SelectionBubbleState, type SlashState, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultBlockPickerItems, getDefaultSlashMenuItems, openEditorThemeTokenNames, sortBlockPickerItems, sortSlashMenuItems, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
package/dist/index.js
CHANGED
|
@@ -33658,12 +33658,37 @@ var useOpenEditorController = ({
|
|
|
33658
33658
|
};
|
|
33659
33659
|
return controller;
|
|
33660
33660
|
};
|
|
33661
|
-
var
|
|
33661
|
+
var sortMenuItems = (items) => [...items].sort((left, right) => {
|
|
33662
33662
|
const leftOrder = typeof left.order === "number" && Number.isFinite(left.order) ? left.order : Number.POSITIVE_INFINITY;
|
|
33663
33663
|
const rightOrder = typeof right.order === "number" && Number.isFinite(right.order) ? right.order : Number.POSITIVE_INFINITY;
|
|
33664
33664
|
if (leftOrder === rightOrder) return 0;
|
|
33665
33665
|
return leftOrder - rightOrder;
|
|
33666
33666
|
});
|
|
33667
|
+
var sortSlashMenuItems = (items) => sortMenuItems(items);
|
|
33668
|
+
var sortBlockPickerItems = (items) => sortMenuItems(items);
|
|
33669
|
+
var getExtensionInsertMenu = (extension) => extension.insertMenu ?? extension.slashMenu;
|
|
33670
|
+
var getDefaultBlockPickerItems = (controller) => sortBlockPickerItems([
|
|
33671
|
+
...openEditorInsertPresets.map((preset, index) => ({
|
|
33672
|
+
key: preset.key,
|
|
33673
|
+
label: preset.label,
|
|
33674
|
+
group: preset.group,
|
|
33675
|
+
keywords: [preset.key],
|
|
33676
|
+
order: (index + 1) * 100,
|
|
33677
|
+
insert: () => controller.insertBlock(preset.key)
|
|
33678
|
+
})),
|
|
33679
|
+
...controller.extensions.filter((extension) => getExtensionInsertMenu(extension) !== false).map((extension) => {
|
|
33680
|
+
const menu = getExtensionInsertMenu(extension) || void 0;
|
|
33681
|
+
return {
|
|
33682
|
+
key: extension.block.name,
|
|
33683
|
+
label: menu?.label ?? extension.block.label,
|
|
33684
|
+
group: menu?.group ?? extension.block.group,
|
|
33685
|
+
icon: menu?.icon,
|
|
33686
|
+
keywords: menu?.keywords ?? [extension.block.name],
|
|
33687
|
+
order: menu?.order,
|
|
33688
|
+
insert: () => controller.insertBlock(extension.block.name)
|
|
33689
|
+
};
|
|
33690
|
+
})
|
|
33691
|
+
]);
|
|
33667
33692
|
var getDefaultSlashMenuItems = (controller) => {
|
|
33668
33693
|
const internalController = controller;
|
|
33669
33694
|
return sortSlashMenuItems([
|
|
@@ -33699,8 +33724,8 @@ var getDefaultSlashMenuItems = (controller) => {
|
|
|
33699
33724
|
return true;
|
|
33700
33725
|
}
|
|
33701
33726
|
},
|
|
33702
|
-
...controller.extensions.filter((extension) => extension
|
|
33703
|
-
const menu = extension
|
|
33727
|
+
...controller.extensions.filter((extension) => getExtensionInsertMenu(extension) !== false).map((extension) => {
|
|
33728
|
+
const menu = getExtensionInsertMenu(extension) || void 0;
|
|
33704
33729
|
return {
|
|
33705
33730
|
key: extension.block.name,
|
|
33706
33731
|
label: menu?.label ?? extension.block.label,
|
|
@@ -33854,6 +33879,6 @@ var OpenEditorViewer = ({
|
|
|
33854
33879
|
};
|
|
33855
33880
|
var useOpenEditor = useOpenEditorController;
|
|
33856
33881
|
|
|
33857
|
-
export { NodeViewContent, NodeViewWrapper, OpenEditorContent, DragHandle2 as OpenEditorDragHandle, OpenEditorThemeProvider, OpenEditorViewer, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultSlashMenuItems, openEditorThemeTokenNames, sortSlashMenuItems, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
|
33882
|
+
export { NodeViewContent, NodeViewWrapper, OpenEditorContent, DragHandle2 as OpenEditorDragHandle, OpenEditorThemeProvider, OpenEditorViewer, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultBlockPickerItems, getDefaultSlashMenuItems, openEditorThemeTokenNames, sortBlockPickerItems, sortSlashMenuItems, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
|
33858
33883
|
//# sourceMappingURL=index.js.map
|
|
33859
33884
|
//# sourceMappingURL=index.js.map
|