@openeditor/react-native-prose-editor 0.0.2
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/LICENSE +160 -0
- package/README.md +180 -0
- package/android/build.gradle +69 -0
- package/android/consumer-rules.pro +18 -0
- package/android/src/androidTest/AndroidManifest.xml +8 -0
- package/android/src/androidTest/java/com/apollohg/editor/MeasureHeightInstrumentedTest.kt +53 -0
- package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceCollaborationInitialSyncTest.kt +241 -0
- package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceImeRegressionTest.kt +338 -0
- package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceOutsideTapTest.kt +789 -0
- package/android/src/androidTest/java/com/apollohg/editor/NativeDevicePerformanceTest.kt +350 -0
- package/android/src/androidTest/java/com/apollohg/editor/NativeEditorOutsideTapActivity.kt +5 -0
- package/android/src/main/assets/editor-icons/MaterialIcons.json +2236 -0
- package/android/src/main/assets/editor-icons/MaterialIcons.ttf +0 -0
- package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +50 -0
- package/android/src/main/java/com/apollohg/editor/EditorAddons.kt +135 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +4527 -0
- package/android/src/main/java/com/apollohg/editor/EditorHeightBehavior.kt +14 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +999 -0
- package/android/src/main/java/com/apollohg/editor/EditorTheme.kt +474 -0
- package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +199 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +3137 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +561 -0
- package/android/src/main/java/com/apollohg/editor/NativeProseViewerExpoView.kt +315 -0
- package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +1413 -0
- package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +133 -0
- package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +315 -0
- package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +2172 -0
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +399 -0
- package/android/src/sharedTest/java/com/apollohg/editor/NativePerformanceSupport.kt +482 -0
- package/android/src/test/java/com/apollohg/editor/CaretGeometryTest.kt +137 -0
- package/android/src/test/java/com/apollohg/editor/EditorEditTextHardwareKeyTest.kt +321 -0
- package/android/src/test/java/com/apollohg/editor/EditorInputConnectionTest.kt +4202 -0
- package/android/src/test/java/com/apollohg/editor/NativeEditorExpoViewTest.kt +2581 -0
- package/android/src/test/java/com/apollohg/editor/NativeEditorModuleTest.kt +27 -0
- package/android/src/test/java/com/apollohg/editor/NativePerformanceTest.kt +197 -0
- package/android/src/test/java/com/apollohg/editor/NativeProseViewerExpoViewTest.kt +84 -0
- package/android/src/test/java/com/apollohg/editor/NativeToolbarTest.kt +544 -0
- package/android/src/test/java/com/apollohg/editor/PositionBridgeTest.kt +461 -0
- package/android/src/test/java/com/apollohg/editor/RenderBridgeTest.kt +2054 -0
- package/android/src/test/java/com/apollohg/editor/RichTextEditorViewTest.kt +1367 -0
- package/app.plugin.js +62 -0
- package/dist/EditorTheme.d.ts +113 -0
- package/dist/EditorTheme.js +29 -0
- package/dist/EditorToolbar.d.ts +191 -0
- package/dist/EditorToolbar.js +1095 -0
- package/dist/NativeEditorBridge.d.ts +325 -0
- package/dist/NativeEditorBridge.js +933 -0
- package/dist/NativeProseViewer.d.ts +53 -0
- package/dist/NativeProseViewer.js +480 -0
- package/dist/NativeRichTextEditor.d.ts +183 -0
- package/dist/NativeRichTextEditor.js +2574 -0
- package/dist/YjsCollaboration.d.ts +90 -0
- package/dist/YjsCollaboration.js +743 -0
- package/dist/addons.d.ts +100 -0
- package/dist/addons.js +82 -0
- package/dist/heightCache.d.ts +6 -0
- package/dist/heightCache.js +45 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +30 -0
- package/dist/schemas.d.ts +37 -0
- package/dist/schemas.js +263 -0
- package/dist/useNativeEditor.d.ts +42 -0
- package/dist/useNativeEditor.js +124 -0
- package/expo-module.config.json +9 -0
- package/ios/EditorAddons.swift +327 -0
- package/ios/EditorCore.xcframework/Info.plist +44 -0
- package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
- package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
- package/ios/EditorLayoutManager.swift +774 -0
- package/ios/EditorTheme.swift +515 -0
- package/ios/Generated_editor_core.swift +1513 -0
- package/ios/NativeEditorExpoView.swift +3593 -0
- package/ios/NativeEditorModule.swift +624 -0
- package/ios/NativeProseViewerExpoView.swift +276 -0
- package/ios/PositionBridge.swift +558 -0
- package/ios/ReactNativeProseEditor.podspec +49 -0
- package/ios/RenderBridge.swift +1708 -0
- package/ios/RichTextEditorView.swift +6150 -0
- package/ios/Tests/NativePerformanceTests.swift +687 -0
- package/ios/Tests/PositionBridgeTests.swift +706 -0
- package/ios/Tests/RenderBridgeTests.swift +2236 -0
- package/ios/Tests/RichTextEditorViewTests.swift +6548 -0
- package/ios/editor_coreFFI/editor_coreFFI.h +1289 -0
- package/ios/editor_coreFFI/module.modulemap +7 -0
- package/ios/editor_coreFFI.h +904 -0
- package/ios/editor_coreFFI.modulemap +7 -0
- package/package.json +74 -0
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +2563 -0
package/dist/addons.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { EditorMentionTheme } from './EditorTheme';
|
|
2
|
+
import type { DocumentJSON } from './NativeEditorBridge';
|
|
3
|
+
import type { SchemaDefinition, NodeSpec } from './schemas';
|
|
4
|
+
export interface MentionSuggestion {
|
|
5
|
+
key: string;
|
|
6
|
+
title: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
attrs?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export interface MentionQueryChangeEvent {
|
|
12
|
+
query: string;
|
|
13
|
+
trigger: string;
|
|
14
|
+
range: {
|
|
15
|
+
anchor: number;
|
|
16
|
+
head: number;
|
|
17
|
+
};
|
|
18
|
+
isActive: boolean;
|
|
19
|
+
documentVersion?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface MentionSelectEvent {
|
|
22
|
+
trigger: string;
|
|
23
|
+
suggestion: MentionSuggestion;
|
|
24
|
+
attrs: Record<string, unknown>;
|
|
25
|
+
documentVersion?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface MentionSelectionAttrsEvent {
|
|
28
|
+
trigger: string;
|
|
29
|
+
suggestion: MentionSuggestion;
|
|
30
|
+
attrs: Record<string, unknown>;
|
|
31
|
+
range: {
|
|
32
|
+
anchor: number;
|
|
33
|
+
head: number;
|
|
34
|
+
};
|
|
35
|
+
documentVersion?: number;
|
|
36
|
+
}
|
|
37
|
+
export type MentionThemeResolveEvent = MentionSelectionAttrsEvent;
|
|
38
|
+
export interface MentionsAddonConfig {
|
|
39
|
+
trigger?: string;
|
|
40
|
+
suggestions?: readonly MentionSuggestion[];
|
|
41
|
+
theme?: EditorMentionTheme;
|
|
42
|
+
resolveSelectionAttrs?: (event: MentionSelectionAttrsEvent) => Record<string, unknown> | null | undefined;
|
|
43
|
+
resolveTheme?: (event: MentionThemeResolveEvent) => EditorMentionTheme | null | undefined;
|
|
44
|
+
onQueryChange?: (event: MentionQueryChangeEvent) => void;
|
|
45
|
+
onSelect?: (event: MentionSelectEvent) => void;
|
|
46
|
+
}
|
|
47
|
+
export interface EditorAddons {
|
|
48
|
+
mentions?: MentionsAddonConfig;
|
|
49
|
+
}
|
|
50
|
+
export interface SerializedMentionSuggestion {
|
|
51
|
+
key: string;
|
|
52
|
+
title: string;
|
|
53
|
+
subtitle?: string;
|
|
54
|
+
label: string;
|
|
55
|
+
attrs: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
export interface SerializedMentionsAddonConfig {
|
|
58
|
+
trigger: string;
|
|
59
|
+
theme?: EditorMentionTheme;
|
|
60
|
+
resolveSelectionAttrs?: boolean;
|
|
61
|
+
resolveTheme?: boolean;
|
|
62
|
+
suggestions: SerializedMentionSuggestion[];
|
|
63
|
+
}
|
|
64
|
+
export interface SerializedEditorAddons {
|
|
65
|
+
mentions?: SerializedMentionsAddonConfig;
|
|
66
|
+
}
|
|
67
|
+
export type EditorAddonEvent = {
|
|
68
|
+
type: 'mentionsQueryChange';
|
|
69
|
+
query: string;
|
|
70
|
+
trigger: string;
|
|
71
|
+
range: {
|
|
72
|
+
anchor: number;
|
|
73
|
+
head: number;
|
|
74
|
+
};
|
|
75
|
+
isActive: boolean;
|
|
76
|
+
documentVersion?: number;
|
|
77
|
+
} | {
|
|
78
|
+
type: 'mentionsSelectRequest';
|
|
79
|
+
trigger: string;
|
|
80
|
+
suggestionKey: string;
|
|
81
|
+
attrs: Record<string, unknown>;
|
|
82
|
+
range: {
|
|
83
|
+
anchor: number;
|
|
84
|
+
head: number;
|
|
85
|
+
};
|
|
86
|
+
documentVersion?: number;
|
|
87
|
+
updateJson?: string;
|
|
88
|
+
} | {
|
|
89
|
+
type: 'mentionsSelect';
|
|
90
|
+
trigger: string;
|
|
91
|
+
suggestionKey: string;
|
|
92
|
+
attrs: Record<string, unknown>;
|
|
93
|
+
documentVersion?: number;
|
|
94
|
+
};
|
|
95
|
+
export declare const MENTION_NODE_NAME = "mention";
|
|
96
|
+
export declare function mentionNodeSpec(): NodeSpec;
|
|
97
|
+
export declare function withMentionsSchema(schema: SchemaDefinition): SchemaDefinition;
|
|
98
|
+
export declare function normalizeEditorAddons(addons?: EditorAddons): SerializedEditorAddons | undefined;
|
|
99
|
+
export declare function serializeEditorAddons(addons?: EditorAddons): string | undefined;
|
|
100
|
+
export declare function buildMentionFragmentJson(attrs: Record<string, unknown>): DocumentJSON;
|
package/dist/addons.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MENTION_NODE_NAME = void 0;
|
|
4
|
+
exports.mentionNodeSpec = mentionNodeSpec;
|
|
5
|
+
exports.withMentionsSchema = withMentionsSchema;
|
|
6
|
+
exports.normalizeEditorAddons = normalizeEditorAddons;
|
|
7
|
+
exports.serializeEditorAddons = serializeEditorAddons;
|
|
8
|
+
exports.buildMentionFragmentJson = buildMentionFragmentJson;
|
|
9
|
+
exports.MENTION_NODE_NAME = 'mention';
|
|
10
|
+
const DEFAULT_MENTION_TRIGGER = '@';
|
|
11
|
+
function mentionNodeSpec() {
|
|
12
|
+
return {
|
|
13
|
+
name: exports.MENTION_NODE_NAME,
|
|
14
|
+
content: '',
|
|
15
|
+
group: 'inline',
|
|
16
|
+
role: 'inline',
|
|
17
|
+
isVoid: true,
|
|
18
|
+
attrs: {
|
|
19
|
+
label: { default: null },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function withMentionsSchema(schema) {
|
|
24
|
+
const hasMentionNode = schema.nodes.some((node) => node.name === exports.MENTION_NODE_NAME);
|
|
25
|
+
if (hasMentionNode) {
|
|
26
|
+
return schema;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
...schema,
|
|
30
|
+
nodes: [...schema.nodes, mentionNodeSpec()],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function normalizeEditorAddons(addons) {
|
|
34
|
+
if (!addons?.mentions) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const trigger = addons.mentions.trigger?.trim() || DEFAULT_MENTION_TRIGGER;
|
|
38
|
+
const suggestions = (addons.mentions.suggestions ?? []).map((suggestion) => {
|
|
39
|
+
const label = suggestion.label?.trim() || `${trigger}${suggestion.title}`;
|
|
40
|
+
const attrs = {
|
|
41
|
+
label,
|
|
42
|
+
mentionSuggestionChar: trigger,
|
|
43
|
+
...(suggestion.attrs ?? {}),
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
key: suggestion.key,
|
|
47
|
+
title: suggestion.title,
|
|
48
|
+
subtitle: suggestion.subtitle,
|
|
49
|
+
label,
|
|
50
|
+
attrs,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
mentions: {
|
|
55
|
+
trigger,
|
|
56
|
+
theme: addons.mentions.theme,
|
|
57
|
+
...(typeof addons.mentions.resolveSelectionAttrs === 'function'
|
|
58
|
+
? { resolveSelectionAttrs: true }
|
|
59
|
+
: {}),
|
|
60
|
+
...(typeof addons.mentions.resolveTheme === 'function' ? { resolveTheme: true } : {}),
|
|
61
|
+
suggestions,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function serializeEditorAddons(addons) {
|
|
66
|
+
const normalized = normalizeEditorAddons(addons);
|
|
67
|
+
if (!normalized?.mentions) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
return JSON.stringify(normalized);
|
|
71
|
+
}
|
|
72
|
+
function buildMentionFragmentJson(attrs) {
|
|
73
|
+
return {
|
|
74
|
+
type: 'doc',
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: exports.MENTION_NODE_NAME,
|
|
78
|
+
attrs,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const MAX_CACHE_SIZE = 500;
|
|
2
|
+
export declare function computeRenderJsonHash(input: string): number;
|
|
3
|
+
export declare function computeLayoutContextKey(themeJson: string | undefined, containerWidth: number): string;
|
|
4
|
+
export declare function getHeightCache(contentId: string, layoutContextKey: string, renderJsonHash: number): number | null;
|
|
5
|
+
export declare function setHeightCache(contentId: string, layoutContextKey: string, renderJsonHash: number, height: number): void;
|
|
6
|
+
export declare function clearHeightCache(): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_CACHE_SIZE = void 0;
|
|
4
|
+
exports.computeRenderJsonHash = computeRenderJsonHash;
|
|
5
|
+
exports.computeLayoutContextKey = computeLayoutContextKey;
|
|
6
|
+
exports.getHeightCache = getHeightCache;
|
|
7
|
+
exports.setHeightCache = setHeightCache;
|
|
8
|
+
exports.clearHeightCache = clearHeightCache;
|
|
9
|
+
exports.MAX_CACHE_SIZE = 500;
|
|
10
|
+
const cache = new Map();
|
|
11
|
+
function computeRenderJsonHash(input) {
|
|
12
|
+
let hash = 5381;
|
|
13
|
+
for (let i = 0; i < input.length; i++) {
|
|
14
|
+
hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0;
|
|
15
|
+
}
|
|
16
|
+
return hash >>> 0;
|
|
17
|
+
}
|
|
18
|
+
function computeLayoutContextKey(themeJson, containerWidth) {
|
|
19
|
+
return `${themeJson ?? ''}\x00${containerWidth}`;
|
|
20
|
+
}
|
|
21
|
+
function getHeightCache(contentId, layoutContextKey, renderJsonHash) {
|
|
22
|
+
const entry = cache.get(contentId);
|
|
23
|
+
if (!entry)
|
|
24
|
+
return null;
|
|
25
|
+
if (entry.layoutContextKey !== layoutContextKey ||
|
|
26
|
+
entry.renderJsonHash !== renderJsonHash) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
cache.delete(contentId);
|
|
30
|
+
cache.set(contentId, entry);
|
|
31
|
+
return entry.height;
|
|
32
|
+
}
|
|
33
|
+
function setHeightCache(contentId, layoutContextKey, renderJsonHash, height) {
|
|
34
|
+
cache.delete(contentId);
|
|
35
|
+
if (cache.size >= exports.MAX_CACHE_SIZE) {
|
|
36
|
+
const oldestKey = cache.keys().next().value;
|
|
37
|
+
if (oldestKey !== undefined) {
|
|
38
|
+
cache.delete(oldestKey);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
cache.set(contentId, { height, renderJsonHash, layoutContextKey });
|
|
42
|
+
}
|
|
43
|
+
function clearHeightCache() {
|
|
44
|
+
cache.clear();
|
|
45
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { NativeRichTextEditor, type NativeRichTextEditorProps, type NativeRichTextEditorRef, type NativeRichTextEditorCaretRect, type NativeRichTextEditorHeightBehavior, type NativeRichTextEditorToolbarPlacement, type NativeRichTextEditorValueJSONUpdateMode, type NativeRichTextEditorAutoCapitalize, type NativeRichTextEditorKeyboardType, type RemoteSelectionDecoration, type LinkRequestContext, type ImageRequestContext, } from './NativeRichTextEditor';
|
|
2
|
+
export { NativeProseViewer, type NativeProseViewerProps, type NativeProseViewerAddons, type NativeProseViewerMentionsAddonConfig, type NativeProseViewerMentionPrefix, type NativeProseViewerLinkPressEvent, type NativeProseViewerMentionRenderContext, type NativeProseViewerMentionPressEvent, } from './NativeProseViewer';
|
|
3
|
+
export { EditorToolbar, DEFAULT_EDITOR_TOOLBAR_ITEMS, type EditorToolbarProps, type EditorToolbarItem, type EditorToolbarLeafItem, type EditorToolbarGroupChildItem, type EditorToolbarGroupItem, type EditorToolbarGroupPresentation, type EditorToolbarIcon, type EditorToolbarDefaultIconId, type EditorToolbarSFSymbolIcon, type EditorToolbarMaterialIcon, type EditorToolbarCommand, type EditorToolbarHeadingLevel, type EditorToolbarListType, } from './EditorToolbar';
|
|
4
|
+
export type { EditorContentInsets, EditorTheme, EditorTextStyle, EditorLinkTheme, EditorHeadingTheme, EditorListTheme, EditorHorizontalRuleTheme, EditorMentionTheme, EditorToolbarTheme, EditorToolbarAppearance, EditorFontStyle, EditorFontWeight, } from './EditorTheme';
|
|
5
|
+
export { MENTION_NODE_NAME, mentionNodeSpec, withMentionsSchema, buildMentionFragmentJson, type EditorAddons, type MentionsAddonConfig, type MentionSuggestion, type MentionQueryChangeEvent, type MentionSelectionAttrsEvent, type MentionThemeResolveEvent, type MentionSelectEvent, type EditorAddonEvent, } from './addons';
|
|
6
|
+
export { tiptapSchema, prosemirrorSchema, IMAGE_NODE_NAME, imageNodeSpec, withImagesSchema, buildImageFragmentJson, type SchemaDefinition, type NodeSpec, type MarkSpec, type AttrSpec, type ImageNodeAttributes, } from './schemas';
|
|
7
|
+
export { createYjsCollaborationController, useYjsCollaboration, type YjsCollaborationOptions, type YjsCollaborationState, type YjsTransportStatus, type LocalAwarenessState, type LocalAwarenessUser, type UseYjsCollaborationResult, type YjsCollaborationController, } from './YjsCollaboration';
|
|
8
|
+
export type { Selection, ActiveState, HistoryState, EditorUpdate, DocumentJSON, CollaborationPeer, EncodedCollaborationStateInput, } from './NativeEditorBridge';
|
|
9
|
+
export { encodeCollaborationStateBase64, decodeCollaborationStateBase64, } from './NativeEditorBridge';
|
|
10
|
+
export { clearHeightCache } from './heightCache';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clearHeightCache = exports.decodeCollaborationStateBase64 = exports.encodeCollaborationStateBase64 = exports.useYjsCollaboration = exports.createYjsCollaborationController = exports.buildImageFragmentJson = exports.withImagesSchema = exports.imageNodeSpec = exports.IMAGE_NODE_NAME = exports.prosemirrorSchema = exports.tiptapSchema = exports.buildMentionFragmentJson = exports.withMentionsSchema = exports.mentionNodeSpec = exports.MENTION_NODE_NAME = exports.DEFAULT_EDITOR_TOOLBAR_ITEMS = exports.EditorToolbar = exports.NativeProseViewer = exports.NativeRichTextEditor = void 0;
|
|
4
|
+
var NativeRichTextEditor_1 = require("./NativeRichTextEditor");
|
|
5
|
+
Object.defineProperty(exports, "NativeRichTextEditor", { enumerable: true, get: function () { return NativeRichTextEditor_1.NativeRichTextEditor; } });
|
|
6
|
+
var NativeProseViewer_1 = require("./NativeProseViewer");
|
|
7
|
+
Object.defineProperty(exports, "NativeProseViewer", { enumerable: true, get: function () { return NativeProseViewer_1.NativeProseViewer; } });
|
|
8
|
+
var EditorToolbar_1 = require("./EditorToolbar");
|
|
9
|
+
Object.defineProperty(exports, "EditorToolbar", { enumerable: true, get: function () { return EditorToolbar_1.EditorToolbar; } });
|
|
10
|
+
Object.defineProperty(exports, "DEFAULT_EDITOR_TOOLBAR_ITEMS", { enumerable: true, get: function () { return EditorToolbar_1.DEFAULT_EDITOR_TOOLBAR_ITEMS; } });
|
|
11
|
+
var addons_1 = require("./addons");
|
|
12
|
+
Object.defineProperty(exports, "MENTION_NODE_NAME", { enumerable: true, get: function () { return addons_1.MENTION_NODE_NAME; } });
|
|
13
|
+
Object.defineProperty(exports, "mentionNodeSpec", { enumerable: true, get: function () { return addons_1.mentionNodeSpec; } });
|
|
14
|
+
Object.defineProperty(exports, "withMentionsSchema", { enumerable: true, get: function () { return addons_1.withMentionsSchema; } });
|
|
15
|
+
Object.defineProperty(exports, "buildMentionFragmentJson", { enumerable: true, get: function () { return addons_1.buildMentionFragmentJson; } });
|
|
16
|
+
var schemas_1 = require("./schemas");
|
|
17
|
+
Object.defineProperty(exports, "tiptapSchema", { enumerable: true, get: function () { return schemas_1.tiptapSchema; } });
|
|
18
|
+
Object.defineProperty(exports, "prosemirrorSchema", { enumerable: true, get: function () { return schemas_1.prosemirrorSchema; } });
|
|
19
|
+
Object.defineProperty(exports, "IMAGE_NODE_NAME", { enumerable: true, get: function () { return schemas_1.IMAGE_NODE_NAME; } });
|
|
20
|
+
Object.defineProperty(exports, "imageNodeSpec", { enumerable: true, get: function () { return schemas_1.imageNodeSpec; } });
|
|
21
|
+
Object.defineProperty(exports, "withImagesSchema", { enumerable: true, get: function () { return schemas_1.withImagesSchema; } });
|
|
22
|
+
Object.defineProperty(exports, "buildImageFragmentJson", { enumerable: true, get: function () { return schemas_1.buildImageFragmentJson; } });
|
|
23
|
+
var YjsCollaboration_1 = require("./YjsCollaboration");
|
|
24
|
+
Object.defineProperty(exports, "createYjsCollaborationController", { enumerable: true, get: function () { return YjsCollaboration_1.createYjsCollaborationController; } });
|
|
25
|
+
Object.defineProperty(exports, "useYjsCollaboration", { enumerable: true, get: function () { return YjsCollaboration_1.useYjsCollaboration; } });
|
|
26
|
+
var NativeEditorBridge_1 = require("./NativeEditorBridge");
|
|
27
|
+
Object.defineProperty(exports, "encodeCollaborationStateBase64", { enumerable: true, get: function () { return NativeEditorBridge_1.encodeCollaborationStateBase64; } });
|
|
28
|
+
Object.defineProperty(exports, "decodeCollaborationStateBase64", { enumerable: true, get: function () { return NativeEditorBridge_1.decodeCollaborationStateBase64; } });
|
|
29
|
+
var heightCache_1 = require("./heightCache");
|
|
30
|
+
Object.defineProperty(exports, "clearHeightCache", { enumerable: true, get: function () { return heightCache_1.clearHeightCache; } });
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DocumentJSON } from './NativeEditorBridge';
|
|
2
|
+
export interface AttrSpec {
|
|
3
|
+
default?: unknown;
|
|
4
|
+
}
|
|
5
|
+
export interface NodeSpec {
|
|
6
|
+
name: string;
|
|
7
|
+
content: string;
|
|
8
|
+
group?: string;
|
|
9
|
+
attrs?: Record<string, AttrSpec>;
|
|
10
|
+
role: string;
|
|
11
|
+
htmlTag?: string;
|
|
12
|
+
isVoid?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface MarkSpec {
|
|
15
|
+
name: string;
|
|
16
|
+
attrs?: Record<string, AttrSpec>;
|
|
17
|
+
excludes?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SchemaDefinition {
|
|
20
|
+
nodes: NodeSpec[];
|
|
21
|
+
marks: MarkSpec[];
|
|
22
|
+
}
|
|
23
|
+
export interface ImageNodeAttributes {
|
|
24
|
+
src: string;
|
|
25
|
+
alt?: string | null;
|
|
26
|
+
title?: string | null;
|
|
27
|
+
width?: number | null;
|
|
28
|
+
height?: number | null;
|
|
29
|
+
}
|
|
30
|
+
export declare const IMAGE_NODE_NAME = "image";
|
|
31
|
+
export declare function imageNodeSpec(name?: string): NodeSpec;
|
|
32
|
+
export declare function withImagesSchema(schema: SchemaDefinition): SchemaDefinition;
|
|
33
|
+
export declare function buildImageFragmentJson(attrs: ImageNodeAttributes): DocumentJSON;
|
|
34
|
+
export declare const tiptapSchema: SchemaDefinition;
|
|
35
|
+
export declare function defaultEmptyDocument(schema?: SchemaDefinition): DocumentJSON;
|
|
36
|
+
export declare function normalizeDocumentJson(doc: DocumentJSON, schema?: SchemaDefinition): DocumentJSON;
|
|
37
|
+
export declare const prosemirrorSchema: SchemaDefinition;
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prosemirrorSchema = exports.tiptapSchema = exports.IMAGE_NODE_NAME = void 0;
|
|
4
|
+
exports.imageNodeSpec = imageNodeSpec;
|
|
5
|
+
exports.withImagesSchema = withImagesSchema;
|
|
6
|
+
exports.buildImageFragmentJson = buildImageFragmentJson;
|
|
7
|
+
exports.defaultEmptyDocument = defaultEmptyDocument;
|
|
8
|
+
exports.normalizeDocumentJson = normalizeDocumentJson;
|
|
9
|
+
exports.IMAGE_NODE_NAME = 'image';
|
|
10
|
+
const HEADING_LEVELS = [1, 2, 3, 4, 5, 6];
|
|
11
|
+
function imageNodeSpec(name = exports.IMAGE_NODE_NAME) {
|
|
12
|
+
return {
|
|
13
|
+
name,
|
|
14
|
+
content: '',
|
|
15
|
+
group: 'block',
|
|
16
|
+
attrs: {
|
|
17
|
+
src: {},
|
|
18
|
+
alt: { default: null },
|
|
19
|
+
title: { default: null },
|
|
20
|
+
width: { default: null },
|
|
21
|
+
height: { default: null },
|
|
22
|
+
},
|
|
23
|
+
role: 'block',
|
|
24
|
+
htmlTag: 'img',
|
|
25
|
+
isVoid: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function headingNodeSpec(level) {
|
|
29
|
+
return {
|
|
30
|
+
name: `h${level}`,
|
|
31
|
+
content: 'inline*',
|
|
32
|
+
group: 'block',
|
|
33
|
+
role: 'textBlock',
|
|
34
|
+
htmlTag: `h${level}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function withImagesSchema(schema) {
|
|
38
|
+
const hasImageNode = schema.nodes.some((node) => node.name === exports.IMAGE_NODE_NAME);
|
|
39
|
+
if (hasImageNode) {
|
|
40
|
+
return schema;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
...schema,
|
|
44
|
+
nodes: [...schema.nodes, imageNodeSpec()],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function buildImageFragmentJson(attrs) {
|
|
48
|
+
return {
|
|
49
|
+
type: 'doc',
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: exports.IMAGE_NODE_NAME,
|
|
53
|
+
attrs,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const MARKS = [
|
|
59
|
+
{ name: 'bold' },
|
|
60
|
+
{ name: 'italic' },
|
|
61
|
+
{ name: 'underline' },
|
|
62
|
+
{ name: 'strike' },
|
|
63
|
+
{ name: 'link', attrs: { href: {} } },
|
|
64
|
+
];
|
|
65
|
+
exports.tiptapSchema = {
|
|
66
|
+
nodes: [
|
|
67
|
+
{
|
|
68
|
+
name: 'doc',
|
|
69
|
+
content: 'block+',
|
|
70
|
+
role: 'doc',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'paragraph',
|
|
74
|
+
content: 'inline*',
|
|
75
|
+
group: 'block',
|
|
76
|
+
role: 'textBlock',
|
|
77
|
+
htmlTag: 'p',
|
|
78
|
+
},
|
|
79
|
+
...HEADING_LEVELS.map((level) => headingNodeSpec(level)),
|
|
80
|
+
{
|
|
81
|
+
name: 'blockquote',
|
|
82
|
+
content: 'block+',
|
|
83
|
+
group: 'block',
|
|
84
|
+
role: 'block',
|
|
85
|
+
htmlTag: 'blockquote',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'bulletList',
|
|
89
|
+
content: 'listItem+',
|
|
90
|
+
group: 'block',
|
|
91
|
+
role: 'list',
|
|
92
|
+
htmlTag: 'ul',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'orderedList',
|
|
96
|
+
content: 'listItem+',
|
|
97
|
+
group: 'block',
|
|
98
|
+
attrs: { start: { default: 1 } },
|
|
99
|
+
role: 'list',
|
|
100
|
+
htmlTag: 'ol',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'listItem',
|
|
104
|
+
content: 'paragraph block*',
|
|
105
|
+
role: 'listItem',
|
|
106
|
+
htmlTag: 'li',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'hardBreak',
|
|
110
|
+
content: '',
|
|
111
|
+
group: 'inline',
|
|
112
|
+
role: 'hardBreak',
|
|
113
|
+
htmlTag: 'br',
|
|
114
|
+
isVoid: true,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'horizontalRule',
|
|
118
|
+
content: '',
|
|
119
|
+
group: 'block',
|
|
120
|
+
role: 'block',
|
|
121
|
+
htmlTag: 'hr',
|
|
122
|
+
isVoid: true,
|
|
123
|
+
},
|
|
124
|
+
imageNodeSpec(),
|
|
125
|
+
{
|
|
126
|
+
name: 'text',
|
|
127
|
+
content: '',
|
|
128
|
+
group: 'inline',
|
|
129
|
+
role: 'text',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
marks: MARKS,
|
|
133
|
+
};
|
|
134
|
+
function acceptingGroupsForChildCount(content, existingChildCount) {
|
|
135
|
+
const tokens = content
|
|
136
|
+
.trim()
|
|
137
|
+
.split(/\s+/)
|
|
138
|
+
.filter(Boolean)
|
|
139
|
+
.map((token) => {
|
|
140
|
+
const quantifier = token[token.length - 1];
|
|
141
|
+
if (quantifier === '+' || quantifier === '*' || quantifier === '?') {
|
|
142
|
+
return {
|
|
143
|
+
group: token.slice(0, -1),
|
|
144
|
+
min: quantifier === '+' ? 1 : 0,
|
|
145
|
+
max: quantifier === '?' ? 1 : null,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
group: token,
|
|
150
|
+
min: 1,
|
|
151
|
+
max: 1,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
let remaining = existingChildCount;
|
|
155
|
+
const acceptingGroups = [];
|
|
156
|
+
for (const token of tokens) {
|
|
157
|
+
if (remaining >= token.min) {
|
|
158
|
+
const consumed = token.max == null ? remaining : Math.min(remaining, token.max);
|
|
159
|
+
remaining = Math.max(0, remaining - consumed);
|
|
160
|
+
const atMax = token.max != null && consumed >= token.max;
|
|
161
|
+
if (!atMax) {
|
|
162
|
+
acceptingGroups.push(token.group);
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
acceptingGroups.push(token.group);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
return acceptingGroups;
|
|
170
|
+
}
|
|
171
|
+
function defaultEmptyDocument(schema = exports.tiptapSchema) {
|
|
172
|
+
const docNode = schema.nodes.find((node) => node.role === 'doc' || node.name === 'doc');
|
|
173
|
+
const acceptingGroups = docNode == null ? [] : acceptingGroupsForChildCount(docNode.content ?? '', 0);
|
|
174
|
+
const matchingTextBlocks = schema.nodes.filter((node) => node.role === 'textBlock' &&
|
|
175
|
+
acceptingGroups.some((group) => node.name === group || node.group === group));
|
|
176
|
+
const preferredTextBlock = matchingTextBlocks.find((node) => node.htmlTag === 'p' || node.name === 'paragraph') ??
|
|
177
|
+
matchingTextBlocks[0] ??
|
|
178
|
+
schema.nodes.find((node) => node.htmlTag === 'p' || node.name === 'paragraph') ??
|
|
179
|
+
schema.nodes.find((node) => node.role === 'textBlock');
|
|
180
|
+
return {
|
|
181
|
+
type: 'doc',
|
|
182
|
+
content: [{ type: preferredTextBlock?.name ?? 'paragraph' }],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function normalizeDocumentJson(doc, schema = exports.tiptapSchema) {
|
|
186
|
+
const root = doc;
|
|
187
|
+
if (root?.type !== 'doc') {
|
|
188
|
+
return doc;
|
|
189
|
+
}
|
|
190
|
+
if (Array.isArray(root.content) && root.content.length > 0) {
|
|
191
|
+
return doc;
|
|
192
|
+
}
|
|
193
|
+
return defaultEmptyDocument(schema);
|
|
194
|
+
}
|
|
195
|
+
exports.prosemirrorSchema = {
|
|
196
|
+
nodes: [
|
|
197
|
+
{
|
|
198
|
+
name: 'doc',
|
|
199
|
+
content: 'block+',
|
|
200
|
+
role: 'doc',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'paragraph',
|
|
204
|
+
content: 'inline*',
|
|
205
|
+
group: 'block',
|
|
206
|
+
role: 'textBlock',
|
|
207
|
+
htmlTag: 'p',
|
|
208
|
+
},
|
|
209
|
+
...HEADING_LEVELS.map((level) => headingNodeSpec(level)),
|
|
210
|
+
{
|
|
211
|
+
name: 'blockquote',
|
|
212
|
+
content: 'block+',
|
|
213
|
+
group: 'block',
|
|
214
|
+
role: 'block',
|
|
215
|
+
htmlTag: 'blockquote',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'bullet_list',
|
|
219
|
+
content: 'list_item+',
|
|
220
|
+
group: 'block',
|
|
221
|
+
role: 'list',
|
|
222
|
+
htmlTag: 'ul',
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'ordered_list',
|
|
226
|
+
content: 'list_item+',
|
|
227
|
+
group: 'block',
|
|
228
|
+
attrs: { start: { default: 1 } },
|
|
229
|
+
role: 'list',
|
|
230
|
+
htmlTag: 'ol',
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'list_item',
|
|
234
|
+
content: 'paragraph block*',
|
|
235
|
+
role: 'listItem',
|
|
236
|
+
htmlTag: 'li',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'hard_break',
|
|
240
|
+
content: '',
|
|
241
|
+
group: 'inline',
|
|
242
|
+
role: 'hardBreak',
|
|
243
|
+
htmlTag: 'br',
|
|
244
|
+
isVoid: true,
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: 'horizontal_rule',
|
|
248
|
+
content: '',
|
|
249
|
+
group: 'block',
|
|
250
|
+
role: 'block',
|
|
251
|
+
htmlTag: 'hr',
|
|
252
|
+
isVoid: true,
|
|
253
|
+
},
|
|
254
|
+
imageNodeSpec('image'),
|
|
255
|
+
{
|
|
256
|
+
name: 'text',
|
|
257
|
+
content: '',
|
|
258
|
+
group: 'inline',
|
|
259
|
+
role: 'text',
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
marks: MARKS,
|
|
263
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NativeEditorBridge, type ActiveState, type HistoryState, type RenderElement, type Selection } from './NativeEditorBridge';
|
|
2
|
+
export interface UseNativeEditorOptions {
|
|
3
|
+
/** Maximum character length. Omit for no limit. */
|
|
4
|
+
maxLength?: number;
|
|
5
|
+
/** Initial HTML content to load after creation. */
|
|
6
|
+
initialHtml?: string;
|
|
7
|
+
/** Called when content changes after an editing operation. */
|
|
8
|
+
onChange?: (html: string) => void;
|
|
9
|
+
/** Called when selection changes. */
|
|
10
|
+
onSelectionChange?: (selection: Selection) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface UseNativeEditorReturn {
|
|
13
|
+
/** The underlying bridge instance, or null before creation. */
|
|
14
|
+
bridge: NativeEditorBridge | null;
|
|
15
|
+
/** Whether the editor has been created and is ready. */
|
|
16
|
+
isReady: boolean;
|
|
17
|
+
/** Current selection state. */
|
|
18
|
+
selection: Selection;
|
|
19
|
+
/** Currently active marks/nodes at the selection. */
|
|
20
|
+
activeState: ActiveState;
|
|
21
|
+
/** Current undo/redo availability. */
|
|
22
|
+
historyState: HistoryState;
|
|
23
|
+
/** Current render elements. */
|
|
24
|
+
renderElements: RenderElement[];
|
|
25
|
+
/** Toggle a mark (e.g. 'bold', 'italic', 'underline'). */
|
|
26
|
+
toggleMark: (markType: string) => void;
|
|
27
|
+
/** Undo the last operation. */
|
|
28
|
+
undo: () => void;
|
|
29
|
+
/** Redo the last undone operation. */
|
|
30
|
+
redo: () => void;
|
|
31
|
+
/** Toggle blockquote wrapping around the current block selection. */
|
|
32
|
+
toggleBlockquote: () => void;
|
|
33
|
+
/** Toggle a heading level on the current block selection. */
|
|
34
|
+
toggleHeading: (level: 1 | 2 | 3 | 4 | 5 | 6) => void;
|
|
35
|
+
/** Insert text at a position. */
|
|
36
|
+
insertText: (pos: number, text: string) => void;
|
|
37
|
+
/** Delete a range [from, to). */
|
|
38
|
+
deleteRange: (from: number, to: number) => void;
|
|
39
|
+
/** Get the current HTML content. */
|
|
40
|
+
getHtml: () => string;
|
|
41
|
+
}
|
|
42
|
+
export declare function useNativeEditor(options?: UseNativeEditorOptions): UseNativeEditorReturn;
|