@openeditor/react 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 +41 -1
- package/dist/index.d.ts +55 -12
- package/dist/index.js +2923 -736
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -8,17 +8,53 @@ Pass `attachmentRuntime` to `useOpenEditorController` for editable attachments a
|
|
|
8
8
|
|
|
9
9
|
- `useOpenEditorController` for editor state, commands, document exports, and selection state
|
|
10
10
|
- `OpenEditorContent` for the editable Tiptap-backed content surface
|
|
11
|
+
- `OpenEditorBubbleMenu` for Tiptap-owned selection visibility and positioning
|
|
11
12
|
- `OpenEditorViewer` for read-only React rendering
|
|
12
13
|
- `OpenEditorPageHeader` for host-backed page title and icon editing
|
|
13
14
|
- `getDefaultBlockPickerItems` for host-owned block rails, pickers, and command palettes
|
|
14
15
|
- `getDefaultSlashMenuItems` for UI packages that want the built-in insert actions
|
|
15
16
|
- stable-identity block targeting and transaction-backed copy, duplicate, move, and delete commands
|
|
17
|
+
- a first-class `controller.table` domain API for selection-aware row, column, header, cell, and table commands
|
|
16
18
|
- `OpenEditorBlockDragHandle` and `useOpenEditorBlockInteraction` for headless block-handle UIs
|
|
17
19
|
- `defineOpenEditorReactNode` for consumer-owned React blocks
|
|
18
20
|
- `defineOpenEditorReactExtension` for advanced integrations that contribute multiple Tiptap extensions
|
|
19
21
|
|
|
20
22
|
This package intentionally does not import CSS and does not render styled menus. Use `@openeditor/ui` for the optional styled components.
|
|
21
23
|
|
|
24
|
+
## Read-only rendering and URL policy
|
|
25
|
+
|
|
26
|
+
`OpenEditorViewer` renders the portable document through an explicit registry of
|
|
27
|
+
built-in and structural renderers. Unknown nodes are preserved for forward
|
|
28
|
+
readability but carry `data-openeditor-unknown-node` so unsupported content never
|
|
29
|
+
silently appears to be a fully supported block. Built-in viewer output and safe
|
|
30
|
+
HTML export share stable `oe-*` classes and `data-openeditor-*` hooks for document
|
|
31
|
+
semantics such as columns, tasks, toggles, callouts, tables, pages, and files.
|
|
32
|
+
|
|
33
|
+
Viewer URLs use `openEditorPublicUrlPolicy` by default. The policy covers links,
|
|
34
|
+
images, pages, and attachments, including snapshots returned by page and
|
|
35
|
+
attachment runtimes. It accepts HTTP(S) and ordinary relative references, plus
|
|
36
|
+
`mailto:` and `tel:` for text links, while rejecting executable and local-preview
|
|
37
|
+
schemes. Owner previews can opt into a narrowly scoped policy:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import {
|
|
41
|
+
OpenEditorViewer,
|
|
42
|
+
openEditorPublicUrlPolicy,
|
|
43
|
+
type OpenEditorUrlPolicy,
|
|
44
|
+
} from "@openeditor/react";
|
|
45
|
+
|
|
46
|
+
const previewUrlPolicy: OpenEditorUrlPolicy = (value, context) => {
|
|
47
|
+
if (context === "attachment" && value.startsWith("blob:")) return value;
|
|
48
|
+
return openEditorPublicUrlPolicy(value, context);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
<OpenEditorViewer document={document} urlPolicy={previewUrlPolicy} />;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Custom viewer renderers receive both `urlPolicy` and a typed `resolveUrl` helper.
|
|
55
|
+
The host remains responsible for arbitrary custom renderer output and for actions
|
|
56
|
+
performed inside `openPage` or `openAttachment` callbacks.
|
|
57
|
+
|
|
22
58
|
## Block actions
|
|
23
59
|
|
|
24
60
|
Every addressable node has a persistent `openeditor-id`. The block interaction
|
|
@@ -208,7 +244,11 @@ const productCard = defineOpenEditorReactNode({
|
|
|
208
244
|
keywords: ["product", "commerce", "card"],
|
|
209
245
|
order: 250,
|
|
210
246
|
},
|
|
211
|
-
viewer: ({ node }) =>
|
|
247
|
+
viewer: ({ node, resolveUrl }) => (
|
|
248
|
+
<article>
|
|
249
|
+
<a href={resolveUrl(node.attrs?.href, "link")}>{String(node.attrs?.title ?? "")}</a>
|
|
250
|
+
</article>
|
|
251
|
+
),
|
|
212
252
|
exporters: {
|
|
213
253
|
html: {
|
|
214
254
|
acmeProductCard: ({ node, escapeHtml }) =>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, CSSProperties, RefObject, ComponentType } from 'react';
|
|
3
|
-
import { OpenEditorBlockRef, OpenEditorDocument, BlockSpec, ProseMirrorNode, OpenEditorPageRuntime, OpenEditorAttachmentRuntime, OpenEditorPageSnapshot, OpenEditorAuthoringCapabilities } from '@openeditor/core';
|
|
4
|
-
export { OpenEditorBlockRef, OpenEditorPageRuntime, OpenEditorPageSnapshot } from '@openeditor/core';
|
|
3
|
+
import { OpenEditorBlockRef, OpenEditorDocument, BlockSpec, ProseMirrorNode, OpenEditorUrlPolicy, OpenEditorUrlContext, OpenEditorPageRuntime, OpenEditorAttachmentRuntime, OpenEditorPageSnapshot, OpenEditorAuthoringCapabilities } from '@openeditor/core';
|
|
4
|
+
export { OpenEditorBlockRef, OpenEditorPageRuntime, OpenEditorPageSnapshot, OpenEditorUrlContext, OpenEditorUrlPolicy, openEditorPublicUrlPolicy, openEditorUnsafeUrlPolicy } from '@openeditor/core';
|
|
5
5
|
import { ExportFormat, OpenEditorExporters } from '@openeditor/exporters';
|
|
6
6
|
export { seedDocument } from '@openeditor/extensions';
|
|
7
|
-
import { AnyExtension, NodeConfig } from '@tiptap/core';
|
|
7
|
+
import { Editor, AnyExtension, NodeConfig } from '@tiptap/core';
|
|
8
8
|
import { ReactNodeViewProps } from '@tiptap/react';
|
|
9
9
|
export { NodeViewContent, NodeViewWrapper, ReactNodeViewProps as OpenEditorNodeViewProps } from '@tiptap/react';
|
|
10
10
|
|
|
@@ -17,7 +17,7 @@ type OpenEditorBlockInteractionStore = {
|
|
|
17
17
|
subscribe: (listener: () => void) => () => void;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
declare const openEditorThemeTokenNames: readonly ["surface", "surfaceRaised", "surfaceMuted", "blockSurface", "text", "textSoft", "heading", "muted", "placeholder", "border", "borderStrong", "structuralLine", "accent", "accentText", "accentStrong", "buttonBackground", "buttonText", "codeBackground", "codeText", "link", "linkHover", "shadow", "fontSans", "fontMono", "radiusSmall", "radiusMedium", "radiusLarge", "spaceBlock", "spaceInline"];
|
|
20
|
+
declare const openEditorThemeTokenNames: readonly ["surface", "surfaceRaised", "surfaceMuted", "blockSurface", "text", "textSoft", "heading", "muted", "placeholder", "border", "borderStrong", "structuralLine", "accent", "accentText", "accentStrong", "buttonBackground", "buttonText", "codeBackground", "codeText", "link", "linkHover", "shadow", "fontSans", "fontMono", "radiusSmall", "radiusMedium", "radiusLarge", "spaceBlock", "spaceInline", "bodyFontSize", "bodyLineHeight", "headingFont", "headingLineHeight", "headingWeight", "heading1Size", "heading2Size", "heading3Size", "heading4Size", "heading5Size", "heading6Size"];
|
|
21
21
|
type OpenEditorThemeToken = (typeof openEditorThemeTokenNames)[number];
|
|
22
22
|
type OpenEditorTheme = Partial<Record<OpenEditorThemeToken, string>>;
|
|
23
23
|
type OpenEditorThemeStyle = CSSProperties & Record<`--oe-${string}`, string | undefined>;
|
|
@@ -29,6 +29,27 @@ declare function OpenEditorThemeProvider({ children, className, theme }: {
|
|
|
29
29
|
theme: OpenEditorTheme;
|
|
30
30
|
}): react.JSX.Element;
|
|
31
31
|
|
|
32
|
+
declare const openEditorTableCommands: readonly ["addRowBefore", "addRowAfter", "deleteRow", "addColumnBefore", "addColumnAfter", "deleteColumn", "toggleHeaderRow", "toggleHeaderColumn", "mergeCells", "splitCell", "deleteTable"];
|
|
33
|
+
type OpenEditorTableCommand = (typeof openEditorTableCommands)[number];
|
|
34
|
+
type OpenEditorTableState = {
|
|
35
|
+
active: boolean;
|
|
36
|
+
rows: number;
|
|
37
|
+
columns: number;
|
|
38
|
+
headerRow: boolean;
|
|
39
|
+
headerColumn: boolean;
|
|
40
|
+
cellSelection: boolean;
|
|
41
|
+
canMergeCells: boolean;
|
|
42
|
+
canSplitCell: boolean;
|
|
43
|
+
};
|
|
44
|
+
type OpenEditorTableController = {
|
|
45
|
+
getState: () => OpenEditorTableState;
|
|
46
|
+
can: (command: OpenEditorTableCommand) => boolean;
|
|
47
|
+
run: (command: OpenEditorTableCommand) => boolean;
|
|
48
|
+
};
|
|
49
|
+
declare const getOpenEditorTableState: (editor: Editor | null) => OpenEditorTableState;
|
|
50
|
+
declare const canRunOpenEditorTableCommand: (editor: Editor | null, command: OpenEditorTableCommand) => boolean;
|
|
51
|
+
declare const runOpenEditorTableCommand: (editor: Editor | null, command: OpenEditorTableCommand) => boolean;
|
|
52
|
+
|
|
32
53
|
type OpenEditorReactProps = OpenEditorAuthoringCapabilities & {
|
|
33
54
|
initialDocument?: OpenEditorDocument;
|
|
34
55
|
editable?: boolean;
|
|
@@ -65,6 +86,8 @@ type OpenEditorController = {
|
|
|
65
86
|
setSelectedBlock: (blockName: string) => void;
|
|
66
87
|
getContent: () => OpenEditorDocument;
|
|
67
88
|
setContent: (document: OpenEditorDocument) => void;
|
|
89
|
+
focus: () => void;
|
|
90
|
+
getPositionRect: (position: number) => OpenEditorOverlayRect | null;
|
|
68
91
|
setParagraph: () => void;
|
|
69
92
|
toggleHeading: (level: 1 | 2 | 3 | 4 | 5 | 6) => void;
|
|
70
93
|
toggleBold: () => void;
|
|
@@ -77,6 +100,7 @@ type OpenEditorController = {
|
|
|
77
100
|
toggleTaskList: () => void;
|
|
78
101
|
toggleBlockquote: () => void;
|
|
79
102
|
toggleCodeBlock: () => void;
|
|
103
|
+
table: OpenEditorTableController;
|
|
80
104
|
undo: () => void;
|
|
81
105
|
redo: () => void;
|
|
82
106
|
insertBlock: (blockName?: string, range?: InsertRange) => boolean;
|
|
@@ -100,7 +124,8 @@ type OpenEditorController = {
|
|
|
100
124
|
attachmentRuntime?: OpenEditorAttachmentRuntime<any>;
|
|
101
125
|
enabledBlocks?: readonly string[];
|
|
102
126
|
slashState: SlashState | null;
|
|
103
|
-
|
|
127
|
+
dismissSlashMenu: () => void;
|
|
128
|
+
registerSlashMenuKeyboardHandler: (handler: (event: globalThis.KeyboardEvent) => boolean) => () => void;
|
|
104
129
|
};
|
|
105
130
|
type OpenEditorContentProps = {
|
|
106
131
|
controller: OpenEditorController;
|
|
@@ -126,11 +151,6 @@ type SlashState = {
|
|
|
126
151
|
top: number;
|
|
127
152
|
anchorRect?: OpenEditorOverlayRect;
|
|
128
153
|
};
|
|
129
|
-
type SelectionBubbleState = {
|
|
130
|
-
left: number;
|
|
131
|
-
top: number;
|
|
132
|
-
anchorRect?: OpenEditorOverlayRect;
|
|
133
|
-
};
|
|
134
154
|
type OpenEditorSlashMenuIconProps = {
|
|
135
155
|
"aria-hidden"?: boolean;
|
|
136
156
|
className?: string;
|
|
@@ -169,6 +189,8 @@ type OpenEditorBlockPickerItem = {
|
|
|
169
189
|
type OpenEditorViewerRenderer = (context: {
|
|
170
190
|
node: ProseMirrorNode;
|
|
171
191
|
children: ReactNode;
|
|
192
|
+
urlPolicy: OpenEditorUrlPolicy;
|
|
193
|
+
resolveUrl: (value: unknown, context: OpenEditorUrlContext) => string | undefined;
|
|
172
194
|
}) => ReactNode;
|
|
173
195
|
type OpenEditorExtensionMenu = {
|
|
174
196
|
label?: string;
|
|
@@ -210,6 +232,8 @@ type OpenEditorViewerProps = {
|
|
|
210
232
|
extensions?: readonly OpenEditorReactExtension[];
|
|
211
233
|
pageRuntime?: OpenEditorPageRuntime;
|
|
212
234
|
attachmentRuntime?: OpenEditorAttachmentRuntime<any>;
|
|
235
|
+
/** Safe by default. Supply an explicit host policy for trusted preview URLs such as `blob:`. */
|
|
236
|
+
urlPolicy?: OpenEditorUrlPolicy;
|
|
213
237
|
};
|
|
214
238
|
declare module "@tiptap/core" {
|
|
215
239
|
interface Commands<ReturnType> {
|
|
@@ -228,6 +252,25 @@ type OpenEditorPageHeaderProps = {
|
|
|
228
252
|
/** Canonical Notion-style page metadata editor shared by host page surfaces. */
|
|
229
253
|
declare const OpenEditorPageHeader: ({ page, runtime, className, onPageChange, }: OpenEditorPageHeaderProps) => react.JSX.Element;
|
|
230
254
|
declare const useOpenEditorController: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, pageRuntime, attachmentRuntime, enabledBlocks, slashMenuItems, extensions, blockActions, }?: OpenEditorReactProps) => OpenEditorController;
|
|
255
|
+
type OpenEditorBubbleMenuProps = {
|
|
256
|
+
controller: OpenEditorController;
|
|
257
|
+
children: ReactNode;
|
|
258
|
+
className?: string;
|
|
259
|
+
container?: HTMLElement | null;
|
|
260
|
+
scrollTarget?: HTMLElement | Window | null;
|
|
261
|
+
style?: CSSProperties;
|
|
262
|
+
};
|
|
263
|
+
type OpenEditorTableBubbleMenuProps = {
|
|
264
|
+
controller: OpenEditorController;
|
|
265
|
+
children: (state: OpenEditorTableState) => ReactNode;
|
|
266
|
+
className?: string;
|
|
267
|
+
container?: HTMLElement | null;
|
|
268
|
+
style?: CSSProperties;
|
|
269
|
+
};
|
|
270
|
+
/** Selection-aware positioning and lifecycle owned by Tiptap's BubbleMenu plugin. */
|
|
271
|
+
declare const OpenEditorBubbleMenu: ({ controller, children, className, container, scrollTarget, style, }: OpenEditorBubbleMenuProps) => react.JSX.Element | null;
|
|
272
|
+
/** A table-owned contextual surface, anchored to the complete selected table. */
|
|
273
|
+
declare const OpenEditorTableBubbleMenu: ({ controller, children, className, container, style, }: OpenEditorTableBubbleMenuProps) => react.JSX.Element | null;
|
|
231
274
|
declare const useOpenEditorBlockInteraction: (controller: OpenEditorController) => OpenEditorBlockInteractionSnapshot;
|
|
232
275
|
type OpenEditorBlockDragHandleProps = {
|
|
233
276
|
controller: OpenEditorController;
|
|
@@ -250,7 +293,7 @@ declare const sortBlockPickerItems: (items: readonly OpenEditorBlockPickerItem[]
|
|
|
250
293
|
declare const getDefaultBlockPickerItems: (controller: OpenEditorController) => OpenEditorBlockPickerItem[];
|
|
251
294
|
declare const getDefaultSlashMenuItems: (controller: OpenEditorController) => OpenEditorSlashMenuItem[];
|
|
252
295
|
declare const OpenEditorContent: ({ controller, className, }: OpenEditorContentProps) => react.JSX.Element;
|
|
253
|
-
declare const OpenEditorViewer: ({ document, className, renderers, extensions, pageRuntime, attachmentRuntime, }: OpenEditorViewerProps) => react.JSX.Element;
|
|
296
|
+
declare const OpenEditorViewer: ({ document, className, renderers, extensions, pageRuntime, attachmentRuntime, urlPolicy, }: OpenEditorViewerProps) => react.JSX.Element;
|
|
254
297
|
declare const useOpenEditor: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, pageRuntime, attachmentRuntime, enabledBlocks, slashMenuItems, extensions, blockActions, }?: OpenEditorReactProps) => OpenEditorController;
|
|
255
298
|
|
|
256
|
-
export { type InsertRange, type OpenEditorBlockAction, type OpenEditorBlockActionContext, OpenEditorBlockDragHandle, type OpenEditorBlockDragHandleProps, type OpenEditorBlockPickerItem, OpenEditorContent, type OpenEditorContentProps, type OpenEditorController, type OpenEditorExtensionMenu, type OpenEditorOverlayRect, OpenEditorPageHeader, type OpenEditorPageHeaderProps, 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
|
|
299
|
+
export { type InsertRange, type OpenEditorBlockAction, type OpenEditorBlockActionContext, OpenEditorBlockDragHandle, type OpenEditorBlockDragHandleProps, type OpenEditorBlockPickerItem, OpenEditorBubbleMenu, type OpenEditorBubbleMenuProps, OpenEditorContent, type OpenEditorContentProps, type OpenEditorController, type OpenEditorExtensionMenu, type OpenEditorOverlayRect, OpenEditorPageHeader, type OpenEditorPageHeaderProps, type OpenEditorReactConfig, type OpenEditorReactExtension, type OpenEditorReactNodeExtension, type OpenEditorReactProps, type OpenEditorSlashMenuIcon, type OpenEditorSlashMenuIconProps, type OpenEditorSlashMenuItem, OpenEditorTableBubbleMenu, type OpenEditorTableBubbleMenuProps, type OpenEditorTableCommand, type OpenEditorTableController, type OpenEditorTableState, type OpenEditorTheme, OpenEditorThemeProvider, type OpenEditorThemeStyle, type OpenEditorThemeToken, OpenEditorViewer, type OpenEditorViewerProps, type OpenEditorViewerRenderer, type SlashState, canRunOpenEditorTableCommand, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultBlockPickerItems, getDefaultSlashMenuItems, getOpenEditorTableState, openEditorTableCommands, openEditorThemeTokenNames, runOpenEditorTableCommand, sortBlockPickerItems, sortSlashMenuItems, useOpenEditor, useOpenEditorBlockInteraction, useOpenEditorController, useOpenEditorThemeStyle };
|