@canvist/react-native 0.0.0 → 0.2.0

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.
@@ -0,0 +1,31 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "CanvistReactNative"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = { type: package["license"] }
11
+ s.author = { "Ifiok Jr." => "support@canvist.dev" }
12
+ s.source = { git: "https://github.com/canvist/canvist.git", tag: "v#{s.version}" }
13
+
14
+ s.platforms = { ios: "17.0" }
15
+ s.source_files = "ios/**/*.{h,mm}"
16
+ s.private_header_files = "ios/**/*.h"
17
+
18
+ # The native editor and its hosting (`CanvistHostView`, `CanvistHostCalls`):
19
+ # `platforms/apple/Canvist.podspec` in the canvist repository, which the
20
+ # app's Podfile points at.
21
+ s.dependency "Canvist", s.version.to_s
22
+ # Set before `install_modules_dependencies`, which adds its own settings to
23
+ # these: no Intel simulator slice, like `Canvist`, and `Canvist-Swift.h`,
24
+ # which a static Swift pod does not put on its dependents' search paths.
25
+ s.pod_target_xcconfig = {
26
+ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" => "x86_64",
27
+ "HEADER_SEARCH_PATHS" => '"$(PODS_CONFIGURATION_BUILD_DIR)/Canvist/Swift Compatibility Header"',
28
+ }
29
+
30
+ install_modules_dependencies(s)
31
+ end
@@ -0,0 +1,50 @@
1
+ // The React Native glue for canvist's Android editor (`io.github.ifiokjr:canvist-android`).
2
+ import groovy.json.JsonSlurper
3
+
4
+ buildscript {
5
+ ext.getExtOrDefault = { name, fallback ->
6
+ rootProject.ext.has(name) ? rootProject.ext.get(name) : fallback
7
+ }
8
+
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+
14
+ dependencies {
15
+ classpath "com.android.tools.build:gradle:8.7.2"
16
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion', '2.2.0')}"
17
+ }
18
+ }
19
+
20
+ apply plugin: "com.android.library"
21
+ if (project.extensions.findByName("kotlin") == null) {
22
+ apply plugin: "kotlin-android"
23
+ }
24
+ apply plugin: "com.facebook.react"
25
+
26
+ // The editor is released in step with this package, so they share a version.
27
+ def canvistVersion = new JsonSlurper().parse(file("../package.json")).version
28
+
29
+ android {
30
+ namespace "io.github.ifiokjr.canvist.reactnative"
31
+ compileSdkVersion getExtOrDefault("compileSdkVersion", 36)
32
+
33
+ defaultConfig {
34
+ minSdkVersion getExtOrDefault("minSdkVersion", 24)
35
+ }
36
+
37
+ compileOptions {
38
+ sourceCompatibility JavaVersion.VERSION_17
39
+ targetCompatibility JavaVersion.VERSION_17
40
+ }
41
+
42
+ sourceSets {
43
+ main.java.srcDirs += "src/main/kotlin"
44
+ }
45
+ }
46
+
47
+ dependencies {
48
+ implementation "com.facebook.react:react-android"
49
+ implementation "io.github.ifiokjr:canvist-android:${canvistVersion}"
50
+ }
@@ -0,0 +1 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
@@ -0,0 +1,32 @@
1
+ package io.github.ifiokjr.canvist.reactnative
2
+
3
+ import com.facebook.react.bridge.WritableMap
4
+ import com.facebook.react.uimanager.events.Event
5
+
6
+ /** One of the view's events, with its payload. */
7
+ internal class CanvistEditorEvent(
8
+ surfaceId: Int,
9
+ viewId: Int,
10
+ private val name: String,
11
+ private val payload: WritableMap,
12
+ ) : Event<CanvistEditorEvent>(surfaceId, viewId) {
13
+ override fun getEventName() = name
14
+
15
+ override fun getEventData() = payload
16
+
17
+ companion object {
18
+ const val READY = "topEditorReady"
19
+ const val CHANGE = "topEditorChange"
20
+ const val FOCUS = "topEditorFocus"
21
+ const val ERROR = "topEditorError"
22
+
23
+ /** The JavaScript prop each event calls. */
24
+ val registrations =
25
+ mapOf(
26
+ READY to "onEditorReady",
27
+ CHANGE to "onEditorChange",
28
+ FOCUS to "onEditorFocus",
29
+ ERROR to "onEditorError",
30
+ )
31
+ }
32
+ }
@@ -0,0 +1,145 @@
1
+ package io.github.ifiokjr.canvist.reactnative
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReactContext
5
+ import com.facebook.react.bridge.ReadableArray
6
+ import com.facebook.react.bridge.WritableMap
7
+ import com.facebook.react.module.annotations.ReactModule
8
+ import com.facebook.react.uimanager.SimpleViewManager
9
+ import com.facebook.react.uimanager.ThemedReactContext
10
+ import com.facebook.react.uimanager.UIManagerHelper
11
+ import com.facebook.react.uimanager.ViewManagerDelegate
12
+ import com.facebook.react.viewmanagers.CanvistEditorViewManagerDelegate
13
+ import com.facebook.react.viewmanagers.CanvistEditorViewManagerInterface
14
+ import io.github.ifiokjr.canvist.CanvistHostView
15
+ import io.github.ifiokjr.canvist.EditorChange
16
+
17
+ /**
18
+ * The Fabric view manager for `CanvistEditorView`. The editor starts once a
19
+ * view's first props have all arrived; later changes to `extensions` and
20
+ * `content` have no effect, as the JavaScript API documents.
21
+ */
22
+ @ReactModule(name = CanvistEditorViewManager.NAME)
23
+ class CanvistEditorViewManager :
24
+ SimpleViewManager<CanvistHostView>(),
25
+ CanvistEditorViewManagerInterface<CanvistHostView> {
26
+ private val delegate = CanvistEditorViewManagerDelegate(this)
27
+
28
+ /** Props of views whose editors have not started yet. */
29
+ private val pending = HashMap<CanvistHostView, StartProps>()
30
+
31
+ override fun getDelegate(): ViewManagerDelegate<CanvistHostView> = delegate
32
+
33
+ override fun getName() = NAME
34
+
35
+ override fun createViewInstance(context: ThemedReactContext): CanvistHostView = CanvistHostView(context).apply { listener = Events }
36
+
37
+ override fun setEditorId(
38
+ view: CanvistHostView,
39
+ value: String?,
40
+ ) {
41
+ pending.getOrPut(view, ::StartProps).editorId = value
42
+ }
43
+
44
+ override fun setExtensions(
45
+ view: CanvistHostView,
46
+ value: ReadableArray?,
47
+ ) {
48
+ val names = value?.toArrayList()?.filterIsInstance<String>() ?: emptyList()
49
+ pending.getOrPut(view, ::StartProps).extensions = names
50
+ }
51
+
52
+ override fun setContentFormat(
53
+ view: CanvistHostView,
54
+ value: String?,
55
+ ) {
56
+ pending.getOrPut(view, ::StartProps).format = value
57
+ }
58
+
59
+ override fun setContent(
60
+ view: CanvistHostView,
61
+ value: String?,
62
+ ) {
63
+ pending.getOrPut(view, ::StartProps).content = value
64
+ }
65
+
66
+ override fun setFontSize(
67
+ view: CanvistHostView,
68
+ value: Float,
69
+ ) {
70
+ view.fontSize = value
71
+ }
72
+
73
+ override fun onAfterUpdateTransaction(view: CanvistHostView) {
74
+ super.onAfterUpdateTransaction(view)
75
+ val props = pending.remove(view) ?: return
76
+ val editorId = props.editorId?.takeIf { it.isNotEmpty() } ?: return
77
+ view.start(editorId, props.extensions, props.format?.ifEmpty { null }, props.content?.ifEmpty { null })
78
+ }
79
+
80
+ override fun onDropViewInstance(view: CanvistHostView) {
81
+ pending.remove(view)
82
+ view.stop()
83
+ super.onDropViewInstance(view)
84
+ }
85
+
86
+ override fun focus(view: CanvistHostView) = view.focusEditor()
87
+
88
+ override fun blur(view: CanvistHostView) = view.blurEditor()
89
+
90
+ override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> =
91
+ CanvistEditorEvent.registrations.mapValues { (_, prop) -> mapOf("registrationName" to prop) }
92
+
93
+ private class StartProps {
94
+ var editorId: String? = null
95
+ var extensions: List<String> = emptyList()
96
+ var format: String? = null
97
+ var content: String? = null
98
+ }
99
+
100
+ /** Sends each host's reports to JavaScript as the view's events. */
101
+ private object Events : CanvistHostView.Listener {
102
+ override fun onReady(
103
+ view: CanvistHostView,
104
+ editorId: String,
105
+ ) = dispatch(view, CanvistEditorEvent.READY) { putString("editorId", editorId) }
106
+
107
+ override fun onChange(
108
+ view: CanvistHostView,
109
+ change: EditorChange,
110
+ ) = dispatch(view, CanvistEditorEvent.CHANGE) {
111
+ putBoolean("document", change.document)
112
+ putBoolean("selection", change.selection)
113
+ putBoolean("composition", change.composition)
114
+ }
115
+
116
+ override fun onFocusChange(
117
+ view: CanvistHostView,
118
+ focused: Boolean,
119
+ ) = dispatch(view, CanvistEditorEvent.FOCUS) { putBoolean("focused", focused) }
120
+
121
+ override fun onError(
122
+ view: CanvistHostView,
123
+ code: String,
124
+ message: String,
125
+ ) = dispatch(view, CanvistEditorEvent.ERROR) {
126
+ putString("code", code)
127
+ putString("message", message)
128
+ }
129
+
130
+ private fun dispatch(
131
+ view: CanvistHostView,
132
+ name: String,
133
+ payload: WritableMap.() -> Unit,
134
+ ) {
135
+ val context = view.context as? ReactContext ?: return
136
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id) ?: return
137
+ val data = Arguments.createMap().apply(payload)
138
+ dispatcher.dispatchEvent(CanvistEditorEvent(UIManagerHelper.getSurfaceId(view), view.id, name, data))
139
+ }
140
+ }
141
+
142
+ companion object {
143
+ const val NAME = "CanvistEditorView"
144
+ }
145
+ }
@@ -0,0 +1,81 @@
1
+ package io.github.ifiokjr.canvist.reactnative
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.module.annotations.ReactModule
5
+ import io.github.ifiokjr.canvist.Command
6
+ import io.github.ifiokjr.canvist.HostedEditors
7
+ import io.github.ifiokjr.canvist.docFormat
8
+ import io.github.ifiokjr.canvist.selectRangeJson
9
+ import io.github.ifiokjr.canvist.selectionJson
10
+
11
+ /**
12
+ * The `CanvistEditors` TurboModule: synchronous calls, on the JavaScript
13
+ * thread, into the editors [HostedEditors] finds by `editorId`. A failure
14
+ * throws with `[canvist:<code>] <reason>` as its message, which React Native
15
+ * rethrows in JavaScript.
16
+ */
17
+ @ReactModule(name = CanvistEditorsModule.NAME)
18
+ class CanvistEditorsModule(
19
+ context: ReactApplicationContext,
20
+ ) : NativeCanvistEditorsSpec(context) {
21
+ override fun getName() = NAME
22
+
23
+ override fun run(
24
+ editorId: String,
25
+ name: String,
26
+ args: String,
27
+ ): Boolean = HostedEditors.call(editorId) { it.run(Command(name, args)) }
28
+
29
+ override fun can(
30
+ editorId: String,
31
+ name: String,
32
+ args: String,
33
+ ): Boolean = HostedEditors.call(editorId) { it.can(Command(name, args)) }
34
+
35
+ override fun query(
36
+ editorId: String,
37
+ name: String,
38
+ args: String,
39
+ ): String = HostedEditors.call(editorId) { it.query(name, args) }
40
+
41
+ override fun load(
42
+ editorId: String,
43
+ format: String,
44
+ content: String,
45
+ ): Boolean =
46
+ HostedEditors.call(editorId) {
47
+ it.load(docFormat(format), content)
48
+ true
49
+ }
50
+
51
+ override fun exportDocument(
52
+ editorId: String,
53
+ format: String,
54
+ ): String = HostedEditors.call(editorId) { it.export(docFormat(format)) }
55
+
56
+ override fun selection(editorId: String): String = HostedEditors.call(editorId) { it.selectionJson() }
57
+
58
+ override fun select(
59
+ editorId: String,
60
+ range: String,
61
+ ): Boolean = HostedEditors.call(editorId) { it.selectRangeJson(range) }
62
+
63
+ override fun selectAll(editorId: String): Boolean = HostedEditors.call(editorId) { it.selectAll() }
64
+
65
+ override fun insertText(
66
+ editorId: String,
67
+ text: String,
68
+ ): Boolean = HostedEditors.call(editorId) { it.insertText(text) }
69
+
70
+ override fun undo(editorId: String): Boolean = HostedEditors.call(editorId) { it.undo() }
71
+
72
+ override fun redo(editorId: String): Boolean = HostedEditors.call(editorId) { it.redo() }
73
+
74
+ override fun canUndo(editorId: String): Boolean = HostedEditors.call(editorId) { it.canUndo() }
75
+
76
+ override fun canRedo(editorId: String): Boolean = HostedEditors.call(editorId) { it.canRedo() }
77
+
78
+ companion object {
79
+ const val NAME = "CanvistEditors"
80
+ }
81
+ }
@@ -0,0 +1,33 @@
1
+ package io.github.ifiokjr.canvist.reactnative
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import com.facebook.react.uimanager.ViewManager
9
+
10
+ /** canvist's editor view and the module that calls into its editors. */
11
+ class CanvistReactNativePackage : BaseReactPackage() {
12
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> = listOf(CanvistEditorViewManager())
13
+
14
+ override fun getModule(
15
+ name: String,
16
+ reactContext: ReactApplicationContext,
17
+ ): NativeModule? = if (name == CanvistEditorsModule.NAME) CanvistEditorsModule(reactContext) else null
18
+
19
+ override fun getReactModuleInfoProvider() =
20
+ ReactModuleInfoProvider {
21
+ mapOf(
22
+ CanvistEditorsModule.NAME to
23
+ ReactModuleInfo(
24
+ name = CanvistEditorsModule.NAME,
25
+ className = CanvistEditorsModule.NAME,
26
+ canOverrideExistingModule = false,
27
+ needsEagerInit = false,
28
+ isCxxModule = false,
29
+ isTurboModule = true,
30
+ ),
31
+ )
32
+ }
33
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The Fabric component spec for the native editor view: React Native's
3
+ * codegen reads this file to generate the iOS and Android glue, so it keeps
4
+ * to the shapes codegen understands.
5
+ *
6
+ * @module
7
+ */
8
+ import type * as React from "react";
9
+ import type { CodegenTypes, HostComponent, ViewProps } from "react-native";
10
+ /** What changed, after every change to the document or selection. */
11
+ export type EditorChangeEvent = Readonly<{
12
+ document: boolean;
13
+ selection: boolean;
14
+ composition: boolean;
15
+ }>;
16
+ /** The view gained or lost focus. */
17
+ export type EditorFocusEvent = Readonly<{
18
+ focused: boolean;
19
+ }>;
20
+ /** The view could not create or load its editor. */
21
+ export type EditorErrorEvent = Readonly<{
22
+ code: string;
23
+ message: string;
24
+ }>;
25
+ /** The view is ready for calls through the `CanvistEditors` module. */
26
+ export type EditorReadyEvent = Readonly<{
27
+ editorId: string;
28
+ }>;
29
+ export interface NativeProps extends ViewProps {
30
+ /** The key the `CanvistEditors` module finds this view's editor by. */
31
+ editorId: string;
32
+ /** The extensions to register, by name. Read when the view is created. */
33
+ extensions: ReadonlyArray<string>;
34
+ /** The format of `content`. Read when the view is created. */
35
+ contentFormat?: string;
36
+ /** The document to start with. Read when the view is created. */
37
+ content?: string;
38
+ /** The body text size before the user's text size setting; 0 is the platform's default. */
39
+ fontSize?: CodegenTypes.WithDefault<CodegenTypes.Float, 0>;
40
+ onEditorReady?: CodegenTypes.DirectEventHandler<EditorReadyEvent>;
41
+ onEditorChange?: CodegenTypes.DirectEventHandler<EditorChangeEvent>;
42
+ onEditorFocus?: CodegenTypes.DirectEventHandler<EditorFocusEvent>;
43
+ onEditorError?: CodegenTypes.DirectEventHandler<EditorErrorEvent>;
44
+ }
45
+ export type CanvistEditorViewType = HostComponent<NativeProps>;
46
+ interface NativeCommands {
47
+ focus: (viewRef: React.ElementRef<CanvistEditorViewType>) => void;
48
+ blur: (viewRef: React.ElementRef<CanvistEditorViewType>) => void;
49
+ }
50
+ export declare const Commands: NativeCommands;
51
+ declare const _default: HostComponent<NativeProps>;
52
+ export default _default;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The TurboModule spec for calls into a view's editor. Every method is
3
+ * synchronous on the JavaScript thread, so commands and queries answer at
4
+ * once, as they do on the web. Methods return a value even when there is
5
+ * nothing to say, because React Native runs `void` methods asynchronously.
6
+ *
7
+ * Failures throw with `[canvist:<code>] <reason>` in the message.
8
+ *
9
+ * @module
10
+ */
11
+ import type { TurboModule } from "react-native";
12
+ export interface Spec extends TurboModule {
13
+ run(editorId: string, name: string, args: string): boolean;
14
+ can(editorId: string, name: string, args: string): boolean;
15
+ query(editorId: string, name: string, args: string): string;
16
+ /** Returns `true`. */
17
+ load(editorId: string, format: string, content: string): boolean;
18
+ exportDocument(editorId: string, format: string): string;
19
+ selection(editorId: string): string;
20
+ /** Returns whether the selection moved. */
21
+ select(editorId: string, range: string): boolean;
22
+ /** Returns whether the selection moved. */
23
+ selectAll(editorId: string): boolean;
24
+ insertText(editorId: string, text: string): boolean;
25
+ undo(editorId: string): boolean;
26
+ redo(editorId: string): boolean;
27
+ canUndo(editorId: string): boolean;
28
+ canRedo(editorId: string): boolean;
29
+ }
30
+ declare const _default: Spec;
31
+ export default _default;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The bridge from the typed editor to one native view: synchronous calls
3
+ * through the `CanvistEditors` TurboModule, and focus through the view's
4
+ * commands.
5
+ *
6
+ * @module
7
+ */
8
+ import type { NativeBridge } from "@canvist/headless/native";
9
+ import type * as React from "react";
10
+ import { type CanvistEditorViewType } from "./CanvistEditorViewNativeComponent.ts";
11
+ import type { Spec } from "./NativeCanvistEditors.ts";
12
+ /** The mounted native view, as React refers to it. */
13
+ export type EditorViewInstance = React.ElementRef<CanvistEditorViewType>;
14
+ /**
15
+ * A bridge to the editor `editorId` names through `module`, focusing the
16
+ * view `view` returns. Focus calls do nothing once the view is gone.
17
+ */
18
+ export declare function nativeBridge(module: Spec, editorId: string, view: () => EditorViewInstance | null): NativeBridge;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The editor component and hooks.
3
+ *
4
+ * @module
5
+ */
6
+ import type { CanvistError, Content, StarterKit } from "@canvist/headless";
7
+ import { NativeEditor } from "@canvist/headless/native";
8
+ import { type ReactElement, type Ref } from "react";
9
+ import type { ViewProps } from "react-native";
10
+ import { type EditorViewInstance } from "./bridge.ts";
11
+ import { type NativeProps } from "./CanvistEditorViewNativeComponent.ts";
12
+ /** The extensions the native editors compile in: TipTap's StarterKit, or some of it. */
13
+ export type NativeExtensions = readonly StarterKit[number][];
14
+ /**
15
+ * A native editor whose commands, queries, and documents are typed from
16
+ * the extensions `E`, with the same API as `@canvist/web`'s editor.
17
+ */
18
+ export type Editor<E extends NativeExtensions> = NativeEditor<E>;
19
+ /** Options for {@link useCanvistEditor} and {@link CanvistEditor}. */
20
+ export interface EditorOptions<E extends NativeExtensions> {
21
+ /** The extensions to register: every StarterKit extension by default. Read once. */
22
+ readonly extensions?: E;
23
+ /** The document to start with: one empty paragraph by default. Read once. */
24
+ readonly content?: Content<E>;
25
+ /** The body text size before the user's text size setting; the platform's body size by default. */
26
+ readonly fontSize?: number;
27
+ /** Called when the view could not create its editor or load `content`. */
28
+ readonly onError?: (error: CanvistError) => void;
29
+ }
30
+ /** Props for {@link CanvistView}: what {@link useCanvistEditor} returns, plus the view's own. */
31
+ export interface CanvistViewProps extends NativeProps {
32
+ readonly ref?: Ref<EditorViewInstance>;
33
+ }
34
+ /** What {@link useCanvistEditor} returns. */
35
+ export interface CanvistEditorHandle<E extends NativeExtensions> {
36
+ /** The editor, once the view has created it; `null` before that. */
37
+ readonly editor: Editor<E> | null;
38
+ /** Spread onto a {@link CanvistView}, alongside its style and accessibility props. */
39
+ readonly props: CanvistViewProps;
40
+ }
41
+ /**
42
+ * The native editor view. Render it with the props {@link useCanvistEditor}
43
+ * returns; give it a size, as it scrolls its own document.
44
+ */
45
+ export declare const CanvistView: import("react-native").HostComponent<NativeProps>;
46
+ /**
47
+ * Create an editor in the {@link CanvistView} you spread `props` onto.
48
+ * `extensions` and `content` are read when the view is created; later
49
+ * changes to them have no effect.
50
+ *
51
+ * ```tsx
52
+ * function Notes() {
53
+ * const { editor, props } = useCanvistEditor({ extensions: [bold, heading] });
54
+ *
55
+ * return (
56
+ * <>
57
+ * <Button title="Bold" onPress={() => editor?.commands.toggleBold()} />
58
+ * <CanvistView {...props} style={{ flex: 1 }} />
59
+ * </>
60
+ * );
61
+ * }
62
+ * ```
63
+ */
64
+ export declare function useCanvistEditor<const E extends NativeExtensions = StarterKit>(options?: EditorOptions<E>): CanvistEditorHandle<E>;
65
+ /**
66
+ * Read `select(editor)` and re-render whenever it changes: after any edit,
67
+ * selection change, or change of focus. `select` must return a primitive
68
+ * or a value that stays the same object while nothing changed, as with
69
+ * `useSyncExternalStore`. Until the editor exists, the value is `fallback`.
70
+ */
71
+ export declare function useEditorState<E extends NativeExtensions, T>(editor: Editor<E> | null, select: (editor: Editor<E>) => T, fallback: T): T;
72
+ /** Props for {@link CanvistEditor}: the editor's options and the view's. */
73
+ export interface CanvistEditorProps<E extends NativeExtensions> extends EditorOptions<E>, ViewProps {
74
+ /** Called once the editor is ready. */
75
+ readonly onReady?: (editor: Editor<E>) => void;
76
+ /** Called after every change to the document, the selection, or focus. */
77
+ readonly onUpdate?: (editor: Editor<E>) => void;
78
+ }
79
+ /**
80
+ * A native canvist editor: the iOS or Android `CanvistView`. Give it a
81
+ * size, as it scrolls its own document.
82
+ *
83
+ * ```tsx
84
+ * <CanvistEditor
85
+ * content={{ format: "markdown", input: "# Notes" }}
86
+ * onUpdate={(editor) => save(editor.export("markdown"))}
87
+ * style={{ flex: 1 }}
88
+ * />
89
+ * ```
90
+ */
91
+ export declare function CanvistEditor<const E extends NativeExtensions = StarterKit>(props: CanvistEditorProps<E>): ReactElement;
package/dist/mod.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The canvist rich-text editor for React Native.
3
+ *
4
+ * `CanvistEditor` shows the native iOS or Android editor: canvist's Rust
5
+ * engine, painted natively and edited through the platform's own text
6
+ * input, not a WebView. Commands, queries, and documents are typed from the
7
+ * extensions you register, with the same API as `@canvist/web`: calling a
8
+ * command you did not register is a type error. Calls are synchronous.
9
+ *
10
+ * ```tsx
11
+ * import { CanvistEditor, bold, heading } from "@canvist/react-native";
12
+ *
13
+ * <CanvistEditor
14
+ * extensions={[bold, heading]}
15
+ * content={{ format: "markdown", input: "# Notes" }}
16
+ * onReady={(editor) => editor.commands.toggleHeading({ level: 2 })}
17
+ * style={{ flex: 1 }}
18
+ * />
19
+ * ```
20
+ *
21
+ * @module
22
+ */
23
+ export type { CanvistError, CommandName, CommandParams, Commands, Content, DocJson, ErrorCode, ExtensionDescriptor, Extensions, Format, Position, Queries, QueryName, QueryParams, QueryResult, Range, Registered, StarterKit, } from "@canvist/headless";
24
+ export * from "@canvist/headless/extensions";
25
+ export { isCanvistError } from "@canvist/headless/native";
26
+ export type { EditorChangeEvent, EditorErrorEvent, EditorFocusEvent, } from "./CanvistEditorViewNativeComponent.ts";
27
+ export { CanvistEditor, type CanvistEditorHandle, type CanvistEditorProps, CanvistView, type CanvistViewProps, type Editor, type EditorOptions, type NativeExtensions, useCanvistEditor, useEditorState, } from "./editor.tsx";
@@ -0,0 +1,10 @@
1
+ #import <React/RCTViewComponentView.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ /// The Fabric component view for `CanvistEditorView`: hosts a `CanvistView`
6
+ /// and turns its changes into events.
7
+ @interface CanvistEditorComponentView : RCTViewComponentView
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END