@openeditor/react 0.0.21 → 0.0.23
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 +14 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +50 -32
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -66,6 +66,7 @@ Keep the extension array referentially stable. Defining extensions at module
|
|
|
66
66
|
scope, as below, is the simplest option.
|
|
67
67
|
|
|
68
68
|
```tsx
|
|
69
|
+
import { PackageOpen } from "lucide-react";
|
|
69
70
|
import {
|
|
70
71
|
defineOpenEditorReactNode,
|
|
71
72
|
NodeViewWrapper,
|
|
@@ -113,7 +114,11 @@ const productCard = defineOpenEditorReactNode({
|
|
|
113
114
|
],
|
|
114
115
|
},
|
|
115
116
|
component: ProductCardNode,
|
|
116
|
-
slashMenu: {
|
|
117
|
+
slashMenu: {
|
|
118
|
+
icon: PackageOpen,
|
|
119
|
+
keywords: ["product", "commerce", "card"],
|
|
120
|
+
order: 250,
|
|
121
|
+
},
|
|
117
122
|
viewer: ({ node }) => <article>{String(node.attrs?.title ?? "")}</article>,
|
|
118
123
|
exporters: {
|
|
119
124
|
html: {
|
|
@@ -138,6 +143,14 @@ Pass the same extension array to `OpenEditorViewer`. The controller automaticall
|
|
|
138
143
|
uses registered exporters for `controller.exports` and registered blocks appear
|
|
139
144
|
in `getDefaultSlashMenuItems`, which powers `@openeditor/ui`.
|
|
140
145
|
|
|
146
|
+
Slash-menu entries accept an optional React `icon` component and numeric `order`.
|
|
147
|
+
OpenEditor assigns built-in entries orders in increments of 100, so consumer
|
|
148
|
+
blocks can be placed between them (for example, `order: 250` appears between
|
|
149
|
+
Heading 1 and Heading 2). Entries with the same order retain their declaration
|
|
150
|
+
order, and entries without an order appear after ordered entries. The same fields
|
|
151
|
+
are available on direct `slashMenuItems`; a menu's explicit `items` prop is also
|
|
152
|
+
sorted by this rule.
|
|
153
|
+
|
|
141
154
|
Block `name` is the stable public identifier. Namespace consumer blocks to avoid
|
|
142
155
|
collisions. `nodeType` is the serialized ProseMirror node type and defaults to
|
|
143
156
|
`name`; use an identifier without punctuation when interoperability requires it.
|
package/dist/index.d.ts
CHANGED
|
@@ -142,11 +142,20 @@ type SelectionBubbleState = {
|
|
|
142
142
|
top: number;
|
|
143
143
|
anchorRect?: OpenEditorOverlayRect;
|
|
144
144
|
};
|
|
145
|
+
type OpenEditorSlashMenuIconProps = {
|
|
146
|
+
"aria-hidden"?: boolean;
|
|
147
|
+
className?: string;
|
|
148
|
+
size?: number;
|
|
149
|
+
strokeWidth?: number;
|
|
150
|
+
};
|
|
151
|
+
type OpenEditorSlashMenuIcon = (props: OpenEditorSlashMenuIconProps) => ReactNode;
|
|
145
152
|
type OpenEditorSlashMenuItem = {
|
|
146
153
|
key: string;
|
|
147
154
|
label: string;
|
|
148
155
|
group: string;
|
|
156
|
+
icon?: OpenEditorSlashMenuIcon;
|
|
149
157
|
keywords?: readonly string[];
|
|
158
|
+
order?: number;
|
|
150
159
|
execute: (context: {
|
|
151
160
|
controller: OpenEditorController;
|
|
152
161
|
range: InsertRange;
|
|
@@ -159,7 +168,9 @@ type OpenEditorViewerRenderer = (context: {
|
|
|
159
168
|
type OpenEditorExtensionMenu = {
|
|
160
169
|
label?: string;
|
|
161
170
|
group?: string;
|
|
171
|
+
icon?: OpenEditorSlashMenuIcon;
|
|
162
172
|
keywords?: readonly string[];
|
|
173
|
+
order?: number;
|
|
163
174
|
};
|
|
164
175
|
/**
|
|
165
176
|
* Complete web integration for a consumer-owned block. The portable `block`
|
|
@@ -197,9 +208,10 @@ declare module "@tiptap/core" {
|
|
|
197
208
|
}
|
|
198
209
|
declare const formatAttachmentSize: (size: number | null) => string;
|
|
199
210
|
declare const useOpenEditorController: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, pageRuntime, attachmentRuntime, slashMenuItems, extensions, blockActions, }?: OpenEditorReactProps) => OpenEditorController;
|
|
211
|
+
declare const sortSlashMenuItems: (items: readonly OpenEditorSlashMenuItem[]) => OpenEditorSlashMenuItem[];
|
|
200
212
|
declare const getDefaultSlashMenuItems: (controller: OpenEditorController) => OpenEditorSlashMenuItem[];
|
|
201
213
|
declare const OpenEditorContent: ({ controller, className, }: OpenEditorContentProps) => react.JSX.Element;
|
|
202
214
|
declare const OpenEditorViewer: ({ document, className, renderers, extensions, pageRuntime, attachmentRuntime, }: OpenEditorViewerProps) => react.JSX.Element;
|
|
203
215
|
declare const useOpenEditor: ({ initialDocument, editable, placeholder, onChange, onFilePasteDrop, pageRuntime, attachmentRuntime, slashMenuItems, extensions, blockActions, }?: OpenEditorReactProps) => OpenEditorController;
|
|
204
216
|
|
|
205
|
-
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 OpenEditorSlashMenuItem, type OpenEditorTheme, OpenEditorThemeProvider, type OpenEditorThemeStyle, type OpenEditorThemeToken, OpenEditorViewer, type OpenEditorViewerProps, type OpenEditorViewerRenderer, type SelectionBubbleState, type SlashState, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultSlashMenuItems, openEditorThemeTokenNames, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -32904,15 +32904,34 @@ var pageSnapshotFromNode = (node) => {
|
|
|
32904
32904
|
href: typeof node.attrs?.href === "string" ? node.attrs.href : null
|
|
32905
32905
|
};
|
|
32906
32906
|
};
|
|
32907
|
+
var useResolvedPageSnapshot = (cached, runtime) => {
|
|
32908
|
+
const [resolved, setResolved] = useState(null);
|
|
32909
|
+
useEffect(() => {
|
|
32910
|
+
let active = true;
|
|
32911
|
+
setResolved(null);
|
|
32912
|
+
if (cached?.pageId && runtime?.resolvePage) {
|
|
32913
|
+
void runtime.resolvePage(cached.pageId).then((page) => {
|
|
32914
|
+
if (active && page) setResolved(page);
|
|
32915
|
+
}).catch(() => {
|
|
32916
|
+
if (active) setResolved(null);
|
|
32917
|
+
});
|
|
32918
|
+
}
|
|
32919
|
+
return () => {
|
|
32920
|
+
active = false;
|
|
32921
|
+
};
|
|
32922
|
+
}, [cached?.pageId, runtime]);
|
|
32923
|
+
return [resolved ?? cached, setResolved];
|
|
32924
|
+
};
|
|
32907
32925
|
var OpenEditorPageNodeView = ({ editor, node, updateAttributes: updateAttributes2 }) => {
|
|
32908
32926
|
const runtime = use(OpenEditorPageRuntimeContext);
|
|
32909
32927
|
const themeStyle = useOpenEditorThemeStyle();
|
|
32910
32928
|
const [creating, setCreating] = useState(false);
|
|
32911
32929
|
const [error, setError] = useState(null);
|
|
32912
|
-
const
|
|
32913
|
-
const
|
|
32930
|
+
const cached = pageSnapshotFromNode(node);
|
|
32931
|
+
const [page, setResolvedPage] = useResolvedPageSnapshot(cached, runtime);
|
|
32932
|
+
const icon = normalizeEmoji(page?.icon, DEFAULT_PAGE_EMOJI);
|
|
32914
32933
|
const openPage = () => {
|
|
32915
|
-
if (
|
|
32934
|
+
if (page) void runtime?.openPage?.(page);
|
|
32916
32935
|
};
|
|
32917
32936
|
const createPage = async () => {
|
|
32918
32937
|
if (!runtime?.createPage || creating) return;
|
|
@@ -32929,10 +32948,11 @@ var OpenEditorPageNodeView = ({ editor, node, updateAttributes: updateAttributes
|
|
|
32929
32948
|
};
|
|
32930
32949
|
const updateIcon = async (nextIcon) => {
|
|
32931
32950
|
updateAttributes2({ icon: nextIcon });
|
|
32932
|
-
if (!
|
|
32951
|
+
if (!page?.pageId || !runtime?.updatePageIcon) return;
|
|
32952
|
+
setResolvedPage({ ...page, icon: nextIcon });
|
|
32933
32953
|
setError(null);
|
|
32934
32954
|
try {
|
|
32935
|
-
await runtime.updatePageIcon(
|
|
32955
|
+
await runtime.updatePageIcon(page.pageId, nextIcon);
|
|
32936
32956
|
} catch (cause) {
|
|
32937
32957
|
setError(cause instanceof Error ? cause.message : "Could not update the page icon.");
|
|
32938
32958
|
}
|
|
@@ -32940,22 +32960,22 @@ var OpenEditorPageNodeView = ({ editor, node, updateAttributes: updateAttributes
|
|
|
32940
32960
|
return /* @__PURE__ */ jsxs(
|
|
32941
32961
|
NodeViewWrapper,
|
|
32942
32962
|
{
|
|
32943
|
-
"aria-label":
|
|
32963
|
+
"aria-label": page ? `Open ${page.title}` : void 0,
|
|
32944
32964
|
className: "oe-page",
|
|
32945
|
-
"data-page-id":
|
|
32965
|
+
"data-page-id": page?.pageId ?? "",
|
|
32946
32966
|
onClick: (event) => {
|
|
32947
32967
|
if (event.target.closest(".oe-emoji-trigger, .oe-emoji-popover")) return;
|
|
32948
32968
|
openPage();
|
|
32949
32969
|
},
|
|
32950
32970
|
onKeyDown: (event) => {
|
|
32951
32971
|
if (event.target.closest(".oe-emoji-trigger, .oe-emoji-popover")) return;
|
|
32952
|
-
if (
|
|
32972
|
+
if (page && (event.key === "Enter" || event.key === " ")) {
|
|
32953
32973
|
event.preventDefault();
|
|
32954
32974
|
openPage();
|
|
32955
32975
|
}
|
|
32956
32976
|
},
|
|
32957
|
-
role:
|
|
32958
|
-
tabIndex:
|
|
32977
|
+
role: page ? "button" : void 0,
|
|
32978
|
+
tabIndex: page ? 0 : void 0,
|
|
32959
32979
|
children: [
|
|
32960
32980
|
/* @__PURE__ */ jsx("span", { contentEditable: false, children: /* @__PURE__ */ jsx(
|
|
32961
32981
|
OpenEditorEmojiPicker,
|
|
@@ -32968,7 +32988,7 @@ var OpenEditorPageNodeView = ({ editor, node, updateAttributes: updateAttributes
|
|
|
32968
32988
|
onEmojiSelect: (nextIcon) => void updateIcon(nextIcon)
|
|
32969
32989
|
}
|
|
32970
32990
|
) }),
|
|
32971
|
-
/* @__PURE__ */ jsx(
|
|
32991
|
+
page && page !== cached ? /* @__PURE__ */ jsx("div", { className: "oe-page-title", contentEditable: false, children: page.title }) : /* @__PURE__ */ jsx(
|
|
32972
32992
|
NodeViewContent,
|
|
32973
32993
|
{
|
|
32974
32994
|
as: "div",
|
|
@@ -32976,7 +32996,7 @@ var OpenEditorPageNodeView = ({ editor, node, updateAttributes: updateAttributes
|
|
|
32976
32996
|
contentEditable: false
|
|
32977
32997
|
}
|
|
32978
32998
|
),
|
|
32979
|
-
!
|
|
32999
|
+
!page && runtime?.createPage && editor.isEditable ? /* @__PURE__ */ jsx(
|
|
32980
33000
|
"button",
|
|
32981
33001
|
{
|
|
32982
33002
|
className: "oe-page-action",
|
|
@@ -33015,20 +33035,7 @@ var Page = Node3.create({
|
|
|
33015
33035
|
var OpenEditorPageViewer = ({ node }) => {
|
|
33016
33036
|
const runtime = use(OpenEditorPageRuntimeContext);
|
|
33017
33037
|
const cached = pageSnapshotFromNode(node);
|
|
33018
|
-
const [
|
|
33019
|
-
useEffect(() => {
|
|
33020
|
-
let active = true;
|
|
33021
|
-
setResolved(null);
|
|
33022
|
-
if (cached?.pageId && runtime?.resolvePage) {
|
|
33023
|
-
void runtime.resolvePage(cached.pageId).then((page2) => {
|
|
33024
|
-
if (active && page2) setResolved(page2);
|
|
33025
|
-
});
|
|
33026
|
-
}
|
|
33027
|
-
return () => {
|
|
33028
|
-
active = false;
|
|
33029
|
-
};
|
|
33030
|
-
}, [cached?.pageId, runtime]);
|
|
33031
|
-
const page = resolved ?? cached;
|
|
33038
|
+
const [page] = useResolvedPageSnapshot(cached, runtime);
|
|
33032
33039
|
const title = page?.title ?? (getNodeText(node) || "Untitled");
|
|
33033
33040
|
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
33034
33041
|
/* @__PURE__ */ jsx("span", { className: "oe-page-icon", "aria-hidden": "true", children: normalizeEmoji(page?.icon, DEFAULT_PAGE_EMOJI) }),
|
|
@@ -33131,7 +33138,7 @@ var createEditorExtensions = (placeholder, customExtensions) => [
|
|
|
33131
33138
|
index_default6,
|
|
33132
33139
|
index_default5,
|
|
33133
33140
|
index_default10.configure({ types: ["heading", "paragraph"] }),
|
|
33134
|
-
index_default4.configure({ placeholder }),
|
|
33141
|
+
index_default4.configure({ placeholder, showOnlyCurrent: true }),
|
|
33135
33142
|
Columns,
|
|
33136
33143
|
Column,
|
|
33137
33144
|
ToggleList,
|
|
@@ -33257,7 +33264,7 @@ var escapeClipboardHtml = (value) => value.replaceAll("&", "&").replaceAll("
|
|
|
33257
33264
|
var useOpenEditorController = ({
|
|
33258
33265
|
initialDocument = seedDocument,
|
|
33259
33266
|
editable = true,
|
|
33260
|
-
placeholder = "
|
|
33267
|
+
placeholder = "Type '/' for commands",
|
|
33261
33268
|
onChange,
|
|
33262
33269
|
onFilePasteDrop,
|
|
33263
33270
|
pageRuntime,
|
|
@@ -33651,20 +33658,28 @@ var useOpenEditorController = ({
|
|
|
33651
33658
|
};
|
|
33652
33659
|
return controller;
|
|
33653
33660
|
};
|
|
33661
|
+
var sortSlashMenuItems = (items) => [...items].sort((left, right) => {
|
|
33662
|
+
const leftOrder = typeof left.order === "number" && Number.isFinite(left.order) ? left.order : Number.POSITIVE_INFINITY;
|
|
33663
|
+
const rightOrder = typeof right.order === "number" && Number.isFinite(right.order) ? right.order : Number.POSITIVE_INFINITY;
|
|
33664
|
+
if (leftOrder === rightOrder) return 0;
|
|
33665
|
+
return leftOrder - rightOrder;
|
|
33666
|
+
});
|
|
33654
33667
|
var getDefaultSlashMenuItems = (controller) => {
|
|
33655
33668
|
const internalController = controller;
|
|
33656
|
-
return [
|
|
33657
|
-
...openEditorInsertPresets.map((preset) => ({
|
|
33669
|
+
return sortSlashMenuItems([
|
|
33670
|
+
...openEditorInsertPresets.map((preset, index) => ({
|
|
33658
33671
|
key: preset.key,
|
|
33659
33672
|
label: preset.label,
|
|
33660
33673
|
group: preset.group,
|
|
33661
33674
|
keywords: [preset.key],
|
|
33675
|
+
order: (index + 1) * 100,
|
|
33662
33676
|
execute: ({ controller: current, range }) => current.insertBlock(preset.key, range)
|
|
33663
33677
|
})),
|
|
33664
33678
|
{
|
|
33665
33679
|
key: "moveBlockUp",
|
|
33666
33680
|
label: "Move Block Up",
|
|
33667
33681
|
group: "block",
|
|
33682
|
+
order: (openEditorInsertPresets.length + 1) * 100,
|
|
33668
33683
|
execute: ({ range }) => {
|
|
33669
33684
|
if (!internalController.editor) return false;
|
|
33670
33685
|
internalController.editor.chain().focus().deleteRange(range).run();
|
|
@@ -33676,6 +33691,7 @@ var getDefaultSlashMenuItems = (controller) => {
|
|
|
33676
33691
|
key: "moveBlockDown",
|
|
33677
33692
|
label: "Move Block Down",
|
|
33678
33693
|
group: "block",
|
|
33694
|
+
order: (openEditorInsertPresets.length + 2) * 100,
|
|
33679
33695
|
execute: ({ range }) => {
|
|
33680
33696
|
if (!internalController.editor) return false;
|
|
33681
33697
|
internalController.editor.chain().focus().deleteRange(range).run();
|
|
@@ -33689,12 +33705,14 @@ var getDefaultSlashMenuItems = (controller) => {
|
|
|
33689
33705
|
key: extension.block.name,
|
|
33690
33706
|
label: menu?.label ?? extension.block.label,
|
|
33691
33707
|
group: menu?.group ?? extension.block.group,
|
|
33708
|
+
icon: menu?.icon,
|
|
33692
33709
|
keywords: menu?.keywords ?? [extension.block.name],
|
|
33710
|
+
order: menu?.order,
|
|
33693
33711
|
execute: ({ controller: current, range }) => current.insertBlock(extension.block.name, range)
|
|
33694
33712
|
};
|
|
33695
33713
|
}),
|
|
33696
33714
|
...controller.slashMenuItems
|
|
33697
|
-
];
|
|
33715
|
+
]);
|
|
33698
33716
|
};
|
|
33699
33717
|
var renderTextWithMarks = (text, marks = [], key) => marks.reduceRight((children, mark, index) => {
|
|
33700
33718
|
const nodeKey = `${key}-${mark.type}-${index}`;
|
|
@@ -33836,6 +33854,6 @@ var OpenEditorViewer = ({
|
|
|
33836
33854
|
};
|
|
33837
33855
|
var useOpenEditor = useOpenEditorController;
|
|
33838
33856
|
|
|
33839
|
-
export { NodeViewContent, NodeViewWrapper, OpenEditorContent, DragHandle2 as OpenEditorDragHandle, OpenEditorThemeProvider, OpenEditorViewer, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultSlashMenuItems, openEditorThemeTokenNames, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
|
33857
|
+
export { NodeViewContent, NodeViewWrapper, OpenEditorContent, DragHandle2 as OpenEditorDragHandle, OpenEditorThemeProvider, OpenEditorViewer, createOpenEditorThemeStyle, defineOpenEditorReactExtension, defineOpenEditorReactNode, formatAttachmentSize, getDefaultSlashMenuItems, openEditorThemeTokenNames, sortSlashMenuItems, useOpenEditor, useOpenEditorController, useOpenEditorThemeStyle };
|
|
33840
33858
|
//# sourceMappingURL=index.js.map
|
|
33841
33859
|
//# sourceMappingURL=index.js.map
|