@openeditor/native 0.0.33 → 0.0.35

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,48 @@
1
+ import type { OpenEditorDocument, OpenEditorPageSnapshot } from "@openeditor/core";
2
+ import type { GlassColorScheme } from "expo-glass-effect";
3
+ import { type OpenEditorRuntimeState, type OpenEditorNativeEffectName, type OpenEditorTheme } from "@openeditor/embedded-runtime";
4
+ import { type ReactNode, type RefAttributes } from "react";
5
+ import { type StyleProp, type ViewStyle } from "react-native";
6
+ import { type WebViewProps } from "react-native-webview";
7
+ import { type OpenEditorNativeController, type OpenEditorNativeEffectHandlers } from "./controller.js";
8
+ import { type OpenEditorNativeToolbarItem } from "./toolbar-host.js";
9
+ import { type OpenEditorNativeContentInsets } from "./native-layout.js";
10
+ export type { OpenEditorNativeContentInsets } from "./native-layout.js";
11
+ export type OpenEditorNativeTheme = Partial<OpenEditorTheme>;
12
+ type EdgeInsets = OpenEditorNativeContentInsets;
13
+ type OwnedWebViewProps = "source" | "onMessage" | "style" | "scrollEnabled" | "nestedScrollEnabled";
14
+ export type OpenEditorNativeProps = {
15
+ initialDocument: OpenEditorDocument;
16
+ /** Page metadata rendered inside the shared, scroll-owned document surface. */
17
+ page?: OpenEditorPageSnapshot;
18
+ editable?: boolean;
19
+ placeholder?: string;
20
+ theme?: OpenEditorNativeTheme;
21
+ contentInsets?: Partial<EdgeInsets>;
22
+ showToolbar?: boolean;
23
+ toolbarItems?: readonly OpenEditorNativeToolbarItem[];
24
+ renderToolbar?: (context: {
25
+ availableNativeEffects: readonly OpenEditorNativeEffectName[];
26
+ blockHandlesVisible: boolean;
27
+ controller: OpenEditorNativeController;
28
+ setBlockHandlesVisible: (visible: boolean) => void;
29
+ state: OpenEditorRuntimeState;
30
+ }) => ReactNode;
31
+ nativeEffects?: OpenEditorNativeEffectHandlers;
32
+ onDocumentChanged?: (change: {
33
+ documentRevision: number;
34
+ origin: "input" | "command";
35
+ }) => void;
36
+ onReady?: (controller: OpenEditorNativeController) => void;
37
+ onError?: (error: Error) => void;
38
+ toolbarContentInset?: number;
39
+ toolbarOffset?: {
40
+ closed?: number;
41
+ opened?: number;
42
+ };
43
+ toolbarColorScheme?: GlassColorScheme;
44
+ toolbarContainerStyle?: StyleProp<ViewStyle>;
45
+ style?: StyleProp<ViewStyle>;
46
+ webViewProps?: Omit<WebViewProps, OwnedWebViewProps>;
47
+ };
48
+ export declare const OpenEditorNative: import("react").ForwardRefExoticComponent<OpenEditorNativeProps & RefAttributes<OpenEditorNativeController>>;
@@ -0,0 +1,214 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { openEditorEmbeddedSurfaceHtml } from "@openeditor/embedded-surface/html";
3
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from "react";
4
+ import { Keyboard, Platform, StyleSheet, useColorScheme, View, } from "react-native";
5
+ import { KeyboardStickyView } from "react-native-keyboard-controller";
6
+ import { WebView, } from "react-native-webview";
7
+ import { emptyOpenEditorNativeState, isOpenEditorNativeLifecycleCancellation, OpenEditorNativeBridge, } from "./controller.js";
8
+ import { OpenEditorNativeToolbar, } from "./toolbar-host.js";
9
+ import { OpenEditorNativeToolbarSurface } from "./toolbar-surface.js";
10
+ import { OPENEDITOR_NATIVE_TOOLBAR_OFFSET, OPENEDITOR_NATIVE_TOOLBAR_CONTENT_INSET, OPENEDITOR_NATIVE_TOOLBAR_HEIGHT, OPENEDITOR_NATIVE_TOOLBAR_RADIUS, resolveOpenEditorNativeContentInsets, } from "./native-layout.js";
11
+ import { resolveOpenEditorNativeTheme } from "./theme.js";
12
+ const DEFAULT_INSETS = { top: 0, right: 16, bottom: 0, left: 16 };
13
+ const HostWebView = WebView;
14
+ export const OpenEditorNative = forwardRef(function OpenEditorNative({ initialDocument, page, editable = true, placeholder = "Start writing…", theme, contentInsets = DEFAULT_INSETS, showToolbar = true, toolbarItems, renderToolbar, nativeEffects, onDocumentChanged, onReady, onError, toolbarContentInset = OPENEDITOR_NATIVE_TOOLBAR_CONTENT_INSET, toolbarOffset = OPENEDITOR_NATIVE_TOOLBAR_OFFSET, toolbarColorScheme, toolbarContainerStyle, style, webViewProps, }, forwardedRef) {
15
+ const systemColorScheme = useColorScheme();
16
+ const resolvedColorScheme = systemColorScheme === "dark" ? "dark" : "light";
17
+ const resolvedTheme = useMemo(() => resolveOpenEditorNativeTheme(theme, resolvedColorScheme), [resolvedColorScheme, theme]);
18
+ const resolvedToolbarColorScheme = toolbarColorScheme ?? resolvedColorScheme;
19
+ const webViewRef = useRef(null);
20
+ const sessionIdRef = useRef(`native_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`);
21
+ const callbacksRef = useRef({
22
+ nativeEffects,
23
+ onDocumentChanged,
24
+ onError,
25
+ onReady,
26
+ });
27
+ callbacksRef.current = { nativeEffects, onDocumentChanged, onError, onReady };
28
+ const initialDocumentRef = useRef(initialDocument);
29
+ const initialConfigRef = useRef({ editable, placeholder, theme: resolvedTheme });
30
+ const initializedRef = useRef(false);
31
+ const bridgeLifetimeRef = useRef(0);
32
+ const [editorState, setEditorState] = useState(emptyOpenEditorNativeState);
33
+ const [blockHandlesVisible, setBlockHandlesVisible] = useState(false);
34
+ const [keyboardVisible, setKeyboardVisible] = useState(() => Keyboard.isVisible?.() ?? false);
35
+ const [bridge] = useState(() => new OpenEditorNativeBridge({
36
+ sessionId: sessionIdRef.current,
37
+ send: (message) => webViewRef.current?.postMessage(message),
38
+ getEffectHandlers: () => callbacksRef.current.nativeEffects,
39
+ }));
40
+ // The packaged HTML is several megabytes. Keeping the source object stable is
41
+ // essential: passing a fresh inline source through React Native on each editor
42
+ // state update can make WKWebView reload it and can terminate its content
43
+ // process under memory pressure.
44
+ const runtimeSource = useMemo(() => ({
45
+ html: openEditorEmbeddedSurfaceHtml,
46
+ baseUrl: "https://openeditor.local/",
47
+ }), []);
48
+ useImperativeHandle(forwardedRef, () => bridge, [bridge]);
49
+ const resolvedInsets = resolveOpenEditorNativeContentInsets({
50
+ contentInsets,
51
+ editable,
52
+ showToolbar,
53
+ toolbarContentInset,
54
+ });
55
+ const availableNativeEffects = Object.keys(nativeEffects ?? {});
56
+ const hostConfig = JSON.stringify({
57
+ availableNativeEffects,
58
+ blockHandles: editable && blockHandlesVisible,
59
+ contentInsets: resolvedInsets,
60
+ page,
61
+ placeholder,
62
+ sessionId: sessionIdRef.current,
63
+ theme: resolvedTheme,
64
+ });
65
+ const injectedConfig = `window.__OPENEDITOR_NATIVE_HOST__=${hostConfig};true;`;
66
+ const hostConfigUpdateScript = `window.dispatchEvent(new CustomEvent("openeditor:host-config",{detail:${JSON.stringify({
67
+ blockHandles: editable && blockHandlesVisible,
68
+ contentInsets: resolvedInsets,
69
+ page,
70
+ placeholder,
71
+ theme: resolvedTheme,
72
+ })}}));true;`;
73
+ const initializeRuntime = useCallback(() => {
74
+ if (!bridge.runtimeReady || initializedRef.current)
75
+ return;
76
+ initializedRef.current = true;
77
+ void bridge
78
+ .initialize(initialDocumentRef.current, initialConfigRef.current.editable)
79
+ .then((result) => {
80
+ bridge.markInitialized();
81
+ setEditorState((state) => ({
82
+ ...state,
83
+ documentRevision: result.documentRevision,
84
+ revision: result.stateRevision,
85
+ editable: initialConfigRef.current.editable,
86
+ }));
87
+ callbacksRef.current.onReady?.(bridge);
88
+ })
89
+ .catch((error) => {
90
+ initializedRef.current = false;
91
+ if (isOpenEditorNativeLifecycleCancellation(error))
92
+ return;
93
+ callbacksRef.current.onError?.(error instanceof Error
94
+ ? error
95
+ : new Error("OpenEditor runtime initialization failed."));
96
+ });
97
+ }, [bridge]);
98
+ useEffect(() => {
99
+ webViewRef.current?.injectJavaScript(hostConfigUpdateScript);
100
+ }, [hostConfigUpdateScript]);
101
+ useEffect(() => {
102
+ const showSubscription = Keyboard.addListener(Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow", () => setKeyboardVisible(true));
103
+ const hideSubscription = Keyboard.addListener(Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide", () => setKeyboardVisible(false));
104
+ return () => {
105
+ showSubscription.remove();
106
+ hideSubscription.remove();
107
+ };
108
+ }, []);
109
+ useEffect(() => {
110
+ const unsubscribe = bridge.subscribe((event) => {
111
+ if (event.type === "ready") {
112
+ initializeRuntime();
113
+ return;
114
+ }
115
+ if (event.type === "stateChanged") {
116
+ setEditorState(event.state);
117
+ return;
118
+ }
119
+ if (event.type === "documentChanged") {
120
+ if (bridge.ready) {
121
+ callbacksRef.current.onDocumentChanged?.({
122
+ documentRevision: event.documentRevision,
123
+ origin: event.origin,
124
+ });
125
+ }
126
+ return;
127
+ }
128
+ if (event.type === "error") {
129
+ callbacksRef.current.onError?.(new Error(`${event.code}: ${event.message}`));
130
+ }
131
+ });
132
+ return unsubscribe;
133
+ }, [bridge, initializeRuntime]);
134
+ useEffect(() => {
135
+ const lifetime = ++bridgeLifetimeRef.current;
136
+ return () => {
137
+ queueMicrotask(() => {
138
+ if (bridgeLifetimeRef.current === lifetime)
139
+ bridge.dispose();
140
+ });
141
+ };
142
+ }, [bridge]);
143
+ useEffect(() => {
144
+ let active = true;
145
+ void bridge
146
+ .command({ type: "setEditable", editable })
147
+ .catch((error) => {
148
+ if (active && !isOpenEditorNativeLifecycleCancellation(error)) {
149
+ callbacksRef.current.onError?.(error instanceof Error
150
+ ? error
151
+ : new Error("OpenEditor could not update editability."));
152
+ }
153
+ });
154
+ return () => {
155
+ active = false;
156
+ };
157
+ }, [bridge, editable]);
158
+ const onMessage = (event) => {
159
+ if (!bridge.receive(event.nativeEvent.data)) {
160
+ callbacksRef.current.onError?.(new Error("OpenEditor runtime sent an invalid bridge message."));
161
+ }
162
+ initializeRuntime();
163
+ };
164
+ const toolbarEnabled = showToolbar && editable;
165
+ const shouldRenderToolbar = showToolbar && editable && editorState.focused && keyboardVisible;
166
+ const toolbar = renderToolbar && shouldRenderToolbar ? (renderToolbar({
167
+ availableNativeEffects,
168
+ blockHandlesVisible,
169
+ controller: bridge,
170
+ setBlockHandlesVisible,
171
+ state: editorState,
172
+ })) : !renderToolbar && toolbarEnabled ? (_jsx(OpenEditorNativeToolbar, { availableNativeEffects: availableNativeEffects, blockHandlesVisible: blockHandlesVisible, controller: bridge, items: toolbarItems, onBlockHandlesVisibleChange: setBlockHandlesVisible, onCommandError: (error) => callbacksRef.current.onError?.(error), state: editorState, style: styles.toolbarContent, theme: resolvedTheme, visible: shouldRenderToolbar })) : null;
173
+ return (_jsxs(View, { style: [
174
+ styles.host,
175
+ { backgroundColor: resolvedTheme.surface },
176
+ style,
177
+ ], children: [_jsx(View, { style: styles.webViewContainer, children: _jsx(HostWebView, { ...webViewProps, allowsBackForwardNavigationGestures: false, bounces: webViewProps?.bounces ?? true, injectedJavaScriptBeforeContentLoaded: injectedConfig, javaScriptEnabled: true, hideKeyboardAccessoryView: webViewProps?.hideKeyboardAccessoryView ?? true, nestedScrollEnabled: true, onLoadStart: (event) => {
178
+ initializedRef.current = false;
179
+ bridge.resetRuntime();
180
+ webViewProps?.onLoadStart?.(event);
181
+ }, onContentProcessDidTerminate: (event) => {
182
+ callbacksRef.current.onError?.(new Error("OpenEditor WebView content process terminated unexpectedly."));
183
+ webViewProps?.onContentProcessDidTerminate?.(event);
184
+ }, onMessage: onMessage, originWhitelist: webViewProps?.originWhitelist ?? [
185
+ "https://openeditor.local",
186
+ "file://*",
187
+ "about:blank",
188
+ ], ref: webViewRef, scrollEnabled: true, source: runtimeSource, style: [
189
+ styles.webView,
190
+ {
191
+ backgroundColor: resolvedTheme.surface,
192
+ },
193
+ ] }) }), toolbarEnabled ? (_jsx(KeyboardStickyView, { offset: toolbarOffset, pointerEvents: "box-none", style: [styles.toolbarContainer, toolbarContainerStyle], children: _jsx(OpenEditorNativeToolbarSurface, { active: shouldRenderToolbar, colorScheme: resolvedToolbarColorScheme, theme: resolvedTheme, children: toolbar }) })) : null] }));
194
+ });
195
+ const styles = StyleSheet.create({
196
+ host: { flex: 1, minHeight: 0 },
197
+ webViewContainer: { flex: 1, minHeight: 0, overflow: "hidden" },
198
+ webView: { flex: 1 },
199
+ toolbarContainer: {
200
+ bottom: 0,
201
+ borderRadius: OPENEDITOR_NATIVE_TOOLBAR_RADIUS,
202
+ height: OPENEDITOR_NATIVE_TOOLBAR_HEIGHT,
203
+ left: 12,
204
+ overflow: "hidden",
205
+ position: "absolute",
206
+ right: 12,
207
+ zIndex: 20,
208
+ },
209
+ toolbarContent: {
210
+ backgroundColor: "transparent",
211
+ borderWidth: 0,
212
+ minHeight: OPENEDITOR_NATIVE_TOOLBAR_HEIGHT,
213
+ },
214
+ });
@@ -0,0 +1,20 @@
1
+ export type OpenEditorNativeContentInsets = {
2
+ top: number;
3
+ right: number;
4
+ bottom: number;
5
+ left: number;
6
+ };
7
+ export declare const OPENEDITOR_NATIVE_TOOLBAR_HEIGHT = 46;
8
+ export declare const OPENEDITOR_NATIVE_TOOLBAR_RADIUS: number;
9
+ export declare const OPENEDITOR_NATIVE_TOOLBAR_CONTENT_INSET = 70;
10
+ export declare const OPENEDITOR_NATIVE_TOOLBAR_OFFSET: {
11
+ readonly closed: 0;
12
+ /** Keep the intentional breathing room above the software keyboard. */
13
+ readonly opened: -8;
14
+ };
15
+ export declare const resolveOpenEditorNativeContentInsets: ({ contentInsets, editable, showToolbar, toolbarContentInset, }: {
16
+ contentInsets: Partial<OpenEditorNativeContentInsets>;
17
+ editable: boolean;
18
+ showToolbar: boolean;
19
+ toolbarContentInset: number;
20
+ }) => OpenEditorNativeContentInsets;
@@ -0,0 +1,15 @@
1
+ export const OPENEDITOR_NATIVE_TOOLBAR_HEIGHT = 46;
2
+ export const OPENEDITOR_NATIVE_TOOLBAR_RADIUS = OPENEDITOR_NATIVE_TOOLBAR_HEIGHT / 2;
3
+ export const OPENEDITOR_NATIVE_TOOLBAR_CONTENT_INSET = 70;
4
+ export const OPENEDITOR_NATIVE_TOOLBAR_OFFSET = {
5
+ closed: 0,
6
+ /** Keep the intentional breathing room above the software keyboard. */
7
+ opened: -8,
8
+ };
9
+ export const resolveOpenEditorNativeContentInsets = ({ contentInsets, editable, showToolbar, toolbarContentInset, }) => ({
10
+ top: contentInsets.top ?? 0,
11
+ right: contentInsets.right ?? 0,
12
+ bottom: (contentInsets.bottom ?? 0) +
13
+ (showToolbar && editable ? toolbarContentInset : 0),
14
+ left: contentInsets.left ?? 0,
15
+ });
@@ -0,0 +1,9 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ export type OpenEditorNativeProviderProps = {
3
+ children: ReactNode;
4
+ };
5
+ /**
6
+ * Owns the native keyboard animation context used by OpenEditor's toolbar.
7
+ * Mount once above every OpenEditorNative instance, normally at the app root.
8
+ */
9
+ export declare function OpenEditorNativeProvider({ children }: OpenEditorNativeProviderProps): ReactElement;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { KeyboardProvider } from "react-native-keyboard-controller";
3
+ /**
4
+ * Owns the native keyboard animation context used by OpenEditor's toolbar.
5
+ * Mount once above every OpenEditorNative instance, normally at the app root.
6
+ */
7
+ export function OpenEditorNativeProvider({ children }) {
8
+ return _jsx(KeyboardProvider, { children: children });
9
+ }
package/dist/theme.d.ts CHANGED
@@ -1,2 +1,32 @@
1
- /** Converts CSS HSL colors into a native-safe hex color and preserves other color strings. */
2
- export declare const normalizeNativeThemeColor: (color: string) => string;
1
+ import type { OpenEditorTheme } from "@openeditor/embedded-runtime";
2
+ export type OpenEditorNativeColorScheme = "light" | "dark";
3
+ declare const LIGHT_THEME: {
4
+ surface: string;
5
+ surfaceRaised: string;
6
+ surfaceMuted: string;
7
+ interactionHover: string;
8
+ interactionSelected: string;
9
+ blockSurface: string;
10
+ text: string;
11
+ textSoft: string;
12
+ heading: string;
13
+ muted: string;
14
+ placeholder: string;
15
+ border: string;
16
+ borderStrong: string;
17
+ structuralLine: string;
18
+ accent: string;
19
+ accentText: string;
20
+ accentStrong: string;
21
+ buttonBackground: string;
22
+ buttonText: string;
23
+ codeBackground: string;
24
+ codeText: string;
25
+ link: string;
26
+ linkHover: string;
27
+ shadow: string;
28
+ fontSans: string;
29
+ };
30
+ export type ResolvedOpenEditorNativeTheme = typeof LIGHT_THEME;
31
+ export declare const resolveOpenEditorNativeTheme: (theme: Partial<OpenEditorTheme> | undefined, colorScheme: OpenEditorNativeColorScheme) => ResolvedOpenEditorNativeTheme;
32
+ export {};
package/dist/theme.js CHANGED
@@ -1,39 +1,58 @@
1
- const HSL_COLOR_PATTERN = /^hsla?\(\s*([-+\d.]+)(?:deg)?[\s,]+([-+\d.]+)%[\s,]+([-+\d.]+)%(?:\s*(?:\/|,)\s*([-+\d.]+%?))?\s*\)$/i;
2
- const clamp = (value, minimum, maximum) => Math.min(Math.max(value, minimum), maximum);
3
- const hueToRgb = (p, q, input) => {
4
- let hue = input;
5
- if (hue < 0)
6
- hue += 1;
7
- if (hue > 1)
8
- hue -= 1;
9
- if (hue < 1 / 6)
10
- return p + (q - p) * 6 * hue;
11
- if (hue < 1 / 2)
12
- return q;
13
- if (hue < 2 / 3)
14
- return p + (q - p) * (2 / 3 - hue) * 6;
15
- return p;
1
+ const LIGHT_THEME = {
2
+ surface: "#ffffff",
3
+ surfaceRaised: "#ffffff",
4
+ surfaceMuted: "#f5f5f5",
5
+ interactionHover: "#f5f5f5",
6
+ interactionSelected: "#e5e5e5",
7
+ blockSurface: "#fafafa",
8
+ text: "#171717",
9
+ textSoft: "#404040",
10
+ heading: "#0a0a0a",
11
+ muted: "#737373",
12
+ placeholder: "#a3a3a3",
13
+ border: "#e5e5e5",
14
+ borderStrong: "#d4d4d4",
15
+ structuralLine: "#e5e5e5",
16
+ accent: "#171717",
17
+ accentText: "#ffffff",
18
+ accentStrong: "#0a0a0a",
19
+ buttonBackground: "#ffffff",
20
+ buttonText: "#171717",
21
+ codeBackground: "#f5f5f5",
22
+ codeText: "#262626",
23
+ link: "#1d4ed8",
24
+ linkHover: "#1e40af",
25
+ shadow: "rgba(0,0,0,0.18)",
26
+ fontSans: '-apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif',
16
27
  };
17
- const toByte = (value) => Math.round(clamp(value, 0, 1) * 255 + 1e-9);
18
- const toHexByte = (value) => value.toString(16).padStart(2, "0");
19
- /** Converts CSS HSL colors into a native-safe hex color and preserves other color strings. */
20
- export const normalizeNativeThemeColor = (color) => {
21
- const match = HSL_COLOR_PATTERN.exec(color.trim());
22
- if (!match)
23
- return color;
24
- const hue = (((Number(match[1]) % 360) + 360) % 360) / 360;
25
- const saturation = clamp(Number(match[2]) / 100, 0, 1);
26
- const lightness = clamp(Number(match[3]) / 100, 0, 1);
27
- const alphaRaw = match[4];
28
- const alpha = alphaRaw
29
- ? clamp(Number(alphaRaw.replace("%", "")) / (alphaRaw.endsWith("%") ? 100 : 1), 0, 1)
30
- : 1;
31
- const q = lightness < 0.5
32
- ? lightness * (1 + saturation)
33
- : lightness + saturation - lightness * saturation;
34
- const p = 2 * lightness - q;
35
- const red = saturation === 0 ? lightness : hueToRgb(p, q, hue + 1 / 3);
36
- const green = saturation === 0 ? lightness : hueToRgb(p, q, hue);
37
- const blue = saturation === 0 ? lightness : hueToRgb(p, q, hue - 1 / 3);
38
- return `#${toHexByte(toByte(red))}${toHexByte(toByte(green))}${toHexByte(toByte(blue))}${alpha < 1 ? toHexByte(toByte(alpha)) : ""}`;
28
+ const DARK_THEME = {
29
+ surface: "#111111",
30
+ surfaceRaised: "#1c1c1e",
31
+ surfaceMuted: "#27272a",
32
+ interactionHover: "#333336",
33
+ interactionSelected: "#3a3a3c",
34
+ blockSurface: "#1c1c1e",
35
+ text: "#f5f5f5",
36
+ textSoft: "#d4d4d4",
37
+ heading: "#fafafa",
38
+ muted: "#a3a3a3",
39
+ placeholder: "#737373",
40
+ border: "#333333",
41
+ borderStrong: "#525252",
42
+ structuralLine: "#333333",
43
+ accent: "#f5f5f5",
44
+ accentText: "#111111",
45
+ accentStrong: "#ffffff",
46
+ buttonBackground: "#27272a",
47
+ buttonText: "#f5f5f5",
48
+ codeBackground: "#1f1f1f",
49
+ codeText: "#e5e5e5",
50
+ link: "#60a5fa",
51
+ linkHover: "#93c5fd",
52
+ shadow: "rgba(0,0,0,0.60)",
53
+ fontSans: '-apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif',
39
54
  };
55
+ export const resolveOpenEditorNativeTheme = (theme, colorScheme) => ({
56
+ ...(colorScheme === "dark" ? DARK_THEME : LIGHT_THEME),
57
+ ...theme,
58
+ });
@@ -0,0 +1,20 @@
1
+ import type { OpenEditorNativeEffectName, OpenEditorRuntimeState } from "@openeditor/embedded-runtime";
2
+ import { type StyleProp, type ViewStyle } from "react-native";
3
+ import type { OpenEditorNativeController } from "./controller.js";
4
+ import type { OpenEditorNativeTheme } from "./native-editor.js";
5
+ import { type OpenEditorNativeToolbarItem } from "./toolbar-items.js";
6
+ export type { OpenEditorNativeToolbarItem } from "./toolbar-items.js";
7
+ export { defaultOpenEditorNativeToolbarItems, openEditorNativeBlockPickerItems, } from "./toolbar-items.js";
8
+ export type OpenEditorNativeToolbarProps = {
9
+ availableNativeEffects?: readonly OpenEditorNativeEffectName[];
10
+ controller: OpenEditorNativeController;
11
+ state: OpenEditorRuntimeState;
12
+ items?: readonly OpenEditorNativeToolbarItem[];
13
+ theme?: OpenEditorNativeTheme;
14
+ style?: StyleProp<ViewStyle>;
15
+ onCommandError?: (error: Error) => void;
16
+ visible?: boolean;
17
+ blockHandlesVisible?: boolean;
18
+ onBlockHandlesVisibleChange?: (visible: boolean) => void;
19
+ };
20
+ export declare const OpenEditorNativeToolbar: import("react").MemoExoticComponent<({ availableNativeEffects, controller, state, items, theme, style, onCommandError, visible, blockHandlesVisible, onBlockHandlesVisibleChange, }: OpenEditorNativeToolbarProps) => import("react").JSX.Element>;