@actualwave/react-native-codeditor 1.1.0 → 1.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +16 -6
  3. package/SKILL.md +469 -0
  4. package/THIRD_PARTY_NOTICES +120 -0
  5. package/app.plugin.js +1 -1
  6. package/lib/module/CodeEditor.js +69 -2
  7. package/lib/typescript/src/CodeEditor.d.ts +20 -2
  8. package/lib/typescript/src/EditorAPI.d.ts +42 -1
  9. package/lib/typescript/src/WebViewAPI.d.ts +4 -1
  10. package/lib/typescript/src/index.d.ts +1 -1
  11. package/package.json +12 -4
  12. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-core.js +39 -0
  13. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-css.js +19 -0
  14. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-glsl.js +1 -0
  15. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-graphql.js +50 -0
  16. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-icu-messageformat.js +1 -0
  17. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-react-native.js +6 -0
  18. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-sksl.js +7 -0
  19. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-sql.js +5 -0
  20. package/src/assets/codemirror/@actualwave_codemirror-lang-embed-tailwind.js +63 -0
  21. package/src/assets/codemirror/@actualwave_codemirror-lang-glsl.js +20 -0
  22. package/src/assets/codemirror/@actualwave_codemirror-lang-icu-messageformat.js +11 -0
  23. package/src/assets/codemirror/@actualwave_codemirror-lang-react-native.js +71 -0
  24. package/src/assets/codemirror/@actualwave_codemirror-lang-sksl.js +7 -2
  25. package/src/assets/codemirror/@codemirror_autocomplete.js +9 -9
  26. package/src/assets/codemirror/@codemirror_commands.js +86 -86
  27. package/src/assets/codemirror/@codemirror_lang-css.js +2 -2
  28. package/src/assets/codemirror/@codemirror_lang-go.js +1 -1
  29. package/src/assets/codemirror/@codemirror_lang-html.js +1 -1
  30. package/src/assets/codemirror/@codemirror_lang-javascript.js +4 -4
  31. package/src/assets/codemirror/@codemirror_lang-jinja.js +1 -1
  32. package/src/assets/codemirror/@codemirror_lang-json.js +1 -1
  33. package/src/assets/codemirror/@codemirror_lang-less.js +1 -1
  34. package/src/assets/codemirror/@codemirror_lang-liquid.js +1 -1
  35. package/src/assets/codemirror/@codemirror_lang-markdown.js +2 -2
  36. package/src/assets/codemirror/@codemirror_lang-python.js +1 -1
  37. package/src/assets/codemirror/@codemirror_lang-sql.js +4 -4
  38. package/src/assets/codemirror/@codemirror_lang-xml.js +1 -1
  39. package/src/assets/codemirror/@codemirror_language.js +11 -11
  40. package/src/assets/codemirror/@codemirror_legacy-modes_mode_clike.js +1 -1
  41. package/src/assets/codemirror/@codemirror_legacy-modes_mode_mathematica.js +1 -1
  42. package/src/assets/codemirror/@codemirror_legacy-modes_mode_oz.js +1 -1
  43. package/src/assets/codemirror/@codemirror_legacy-modes_mode_verilog.js +1 -1
  44. package/src/assets/codemirror/@codemirror_lint.js +5 -5
  45. package/src/assets/codemirror/@codemirror_merge.js +4 -4
  46. package/src/assets/codemirror/@codemirror_search.js +8 -8
  47. package/src/assets/codemirror/@codemirror_state.js +1 -1
  48. package/src/assets/codemirror/@codemirror_theme-one-dark.js +3 -3
  49. package/src/assets/codemirror/@codemirror_view.js +6 -6
  50. package/src/assets/codemirror/@lezer_common.js +2 -2
  51. package/src/assets/codemirror/@lezer_css.js +1 -1
  52. package/src/assets/codemirror/@lezer_javascript.js +1 -1
  53. package/src/assets/codemirror/@lezer_lr.js +1 -1
  54. package/src/assets/codemirror/@lezer_markdown.js +4 -4
  55. package/src/assets/codemirror/@lezer_sass.js +1 -1
  56. package/src/assets/codemirror/_core.js +129 -129
  57. package/src/assets/codemirror-editor.umd.js +130 -17
  58. package/src/assets/editor.html +25 -1
  59. package/lib/typescript/app.plugin.d.ts +0 -3
  60. package/lib/typescript/babel.config.d.ts +0 -10
  61. package/lib/typescript/react-native.config.d.ts +0 -2
  62. package/lib/typescript/scripts/copy-assets.d.ts +0 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ ## 1.2.0
4
+
5
+ ### Added
6
+ - `languages` prop on `<CodeEditor>` and `api.editor.registerLanguage(name, packageName)` for
7
+ language packages that don't follow the `@codemirror/lang-{name}` naming convention
8
+ (e.g. `{ sksl: '@actualwave/codemirror-lang-sksl' }`). The prop registers before the initial
9
+ `language` is resolved.
10
+ - `languageConfig` prop and `setLanguage(name, config?, embeds?)` — options passed to the
11
+ language factory (e.g. `{ jsx: true, typescript: true }`).
12
+ - `embeds` prop, `api.editor.registerTaggedTemplate()` and `api.editor.registerSupportExtension()`
13
+ for tagged-template DSL embeddings and support extensions in `javascript`.
14
+ - `CompletionItem` and `EmbedsConfig` types are now exported.
15
+ - `THIRD_PARTY_NOTICES`, `SKILL.md` and `CHANGELOG.md` are included in the package.
16
+
17
+ ### Changed
18
+ - Updated bundled `@actualwave/codemirror-package` assets to 0.1.4.
19
+ - `sksl` (and other `@actualwave/codemirror-lang-*` packages) are no longer pre-registered by the
20
+ bundled codemirror-package (it was an undocumented built-in in 1.1.0). Pass
21
+ `languages={{ sksl: '@actualwave/codemirror-lang-sksl' }}` or call `api.editor.registerLanguage()`
22
+ before using them; otherwise `setLanguage` rejects with "No language support found".
23
+ - `lib/typescript` no longer contains declaration files for repo config files.
24
+
25
+ ### Fixed
26
+ - Documentation and example for the iOS `editorUri` used `FileSystem.bundleDirectory`, which is not
27
+ available from the default `expo-file-system` entry point in Expo SDK 55. Use
28
+ `new File(Paths.bundle, 'assets/codeditor/editor.html').uri`.
package/README.md CHANGED
@@ -144,16 +144,16 @@ npm install expo-file-system
144
144
 
145
145
  ```tsx
146
146
  import { Platform } from 'react-native';
147
- import * as FileSystem from 'expo-file-system';
147
+ import { File, Paths } from 'expo-file-system';
148
148
 
149
149
  const IOS_EDITOR_URI = Platform.OS === 'ios'
150
- ? (FileSystem.bundleDirectory ?? '') + 'assets/codeditor/editor.html'
150
+ ? new File(Paths.bundle, 'assets/codeditor/editor.html').uri
151
151
  : undefined;
152
152
 
153
153
  <CodeEditor editorUri={IOS_EDITOR_URI} ... />
154
154
  ```
155
155
 
156
- `FileSystem.bundleDirectory` returns the `file://` path to the `.app` folder (e.g.
156
+ `Paths.bundle` is the `.app` folder in the bundle (e.g.
157
157
  `file:///var/containers/Bundle/Application/<UUID>/MyApp.app/`), which is stable on both
158
158
  simulators and real devices regardless of where iOS installed the app.
159
159
 
@@ -224,6 +224,7 @@ export default function EditorScreen() {
224
224
  |---|---|---|---|
225
225
  | `content` | `string` | `''` | Initial document content (see [Content model](#content-model) below). |
226
226
  | `language` | `string` | `undefined` | Syntax language, e.g. `'javascript'`, `'python'`, `'sql'`. The language module is loaded from the bundled assets on first use. |
227
+ | `languages` | `Record<string, string>` | `undefined` | Custom language packages as `{ name: packageName }`, for languages that don't follow the `@codemirror/lang-{name}` convention, e.g. `{ sksl: '@actualwave/codemirror-lang-sksl' }`. Registered before the initial `language` is resolved. The package must be bundled in the WebView assets. |
227
228
  | `extensions` | `ExtensionSpec[]` | `[]` | Additional CodeMirror 6 extension specs. See [Extension specs](#extension-specs). |
228
229
  | `theme` | `string` | `undefined` | Theme name. See [Themes](#themes). |
229
230
  | `viewport` | `ViewportSettings` | `undefined` | Controls the `<meta name="viewport">` tag inside the WebView. |
@@ -314,6 +315,12 @@ api.editor.setLanguage(name: string): Promise<void>
314
315
  // Switches syntax language. Loads the language module on demand.
315
316
  // e.g. await api.editor.setLanguage('python')
316
317
 
318
+ api.editor.registerLanguage(name: string, packageName: string): Promise<void>
319
+ // Maps a language name to a package that doesn't follow @codemirror/lang-{name}.
320
+ // Takes effect on the next setLanguage(). Alternative to the `languages` prop.
321
+ // e.g. await api.editor.registerLanguage('sksl', '@actualwave/codemirror-lang-sksl');
322
+ // await api.editor.setLanguage('sksl')
323
+
317
324
  api.editor.setExtensions(specs: ExtensionSpec[]): Promise<void>
318
325
  // Replaces the active extension set.
319
326
  // e.g. await api.editor.setExtensions(['@codemirror/search'])
@@ -451,9 +458,9 @@ api.editor.unregisterShortcut(key: string): Promise<void>
451
458
 
452
459
  ```tsx
453
460
  <CodeEditor
454
- onInitialized={(api) => {
455
- void api.editor.registerShortcut('Mod-s', 'save');
456
- void api.editor.registerShortcut('Mod-Enter', 'run');
461
+ onInitialized={async (api) => {
462
+ await api.editor.registerShortcut('Mod-s', 'save');
463
+ await api.editor.registerShortcut('Mod-Enter', 'run');
457
464
  }}
458
465
  onShortcut={(name) => {
459
466
  if (name === 'save') handleSave();
@@ -567,6 +574,9 @@ Pass any of these to the `language` prop or `api.editor.setLanguage()`:
567
574
  `less` `lezer` `liquid` `markdown` `php` `python` `rust` `sass` `sql`
568
575
  `vue` `wast` `xml` `yaml`
569
576
 
577
+ Other bundled packages such as `sksl` are not auto-detected — register them with the
578
+ `languages` prop or `api.editor.registerLanguage()`.
579
+
570
580
  Legacy modes (100+ additional languages via `@codemirror/legacy-modes`) can be loaded
571
581
  manually with `api.editor.loadExtension()`:
572
582
 
package/SKILL.md ADDED
@@ -0,0 +1,469 @@
1
+ ---
2
+ name: react-native-codeditor
3
+ description: >
4
+ Embed and control a CodeMirror 6 code editor inside a React Native WebView using
5
+ @actualwave/react-native-codeditor. Use when adding a code editor to a React Native
6
+ app, controlling editor content/language/theme/cursor/selection/history programmatically,
7
+ registering custom keyboard shortcuts, handling editor events (content changes, history
8
+ size, selection), or setting up native asset copying for Android/iOS.
9
+ license: MIT
10
+ compatibility: React Native ≥ 0.71, react-native-webview ≥ 11, Android WebView 61+, iOS with WKWebView. expo-file-system required for iOS URI resolution.
11
+ metadata:
12
+ package: "@actualwave/react-native-codeditor"
13
+ npm: "https://www.npmjs.com/package/@actualwave/react-native-codeditor"
14
+ repository: "https://github.com/burdiuz/react-native-codeditor"
15
+ ---
16
+
17
+ # @actualwave/react-native-codeditor — Agent Skill
18
+
19
+ CodeMirror 6 code editor for React Native, embedded in a WebView with a full bidirectional RPC bridge. Fully offline — all CodeMirror assets are bundled. Works on Android and iOS.
20
+
21
+ ---
22
+
23
+ ## Exports
24
+
25
+ ```ts
26
+ import CodeEditor from '@actualwave/react-native-codeditor';
27
+ // or named (WebViewAPI is the class itself, exported as a value):
28
+ import { CodeEditor, WebViewAPI } from '@actualwave/react-native-codeditor';
29
+
30
+ // Types
31
+ import type {
32
+ CodeEditorProps, // all props for <CodeEditor />
33
+ WebViewAPIHandlers, // handler callbacks
34
+ WebViewRef, // { injectJavaScript, requestFocus? }
35
+ InitialConfig, // { content?, language?, languageConfig?, embeds?, languages?, extensions?, theme?, viewport? }
36
+ EditorAPI, // full interface of api.editor proxy methods
37
+ ExtensionSpec, // string | [string, string] | [string, object] | unknown
38
+ ViewportSettings, // { intialScale?, maximumScale?, minimumScale?, userScalable?, viewportWidth? }
39
+ CursorPosition, // { line: number, ch: number, index: number }
40
+ HistorySize, // { undo: number, redo: number }
41
+ CompletionItem, // { label, type?, detail?, info? }
42
+ EmbedsConfig, // { taggedTemplates?, supportExtensions? }
43
+ } from '@actualwave/react-native-codeditor';
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ npm install @actualwave/react-native-codeditor react-native-webview
52
+ ```
53
+
54
+ **Copy assets to Android** (required — WebView loads these files at runtime):
55
+
56
+ ```bash
57
+ mkdir -p android/app/src/main/assets/codeditor
58
+ cp -r node_modules/@actualwave/react-native-codeditor/src/assets/* android/app/src/main/assets/codeditor/
59
+ ```
60
+
61
+ **Expo (recommended)** — add plugin to `app.json`, then `expo prebuild`:
62
+
63
+ ```json
64
+ { "expo": { "plugins": ["@actualwave/react-native-codeditor"] } }
65
+ ```
66
+
67
+ **iOS** — requires `expo-file-system` for the runtime bundle path:
68
+
69
+ ```bash
70
+ npm install expo-file-system
71
+ ```
72
+
73
+ ```tsx
74
+ import { File, Paths } from 'expo-file-system';
75
+ const IOS_EDITOR_URI = Platform.OS === 'ios'
76
+ ? new File(Paths.bundle, 'assets/codeditor/editor.html').uri
77
+ : undefined;
78
+ <CodeEditor editorUri={IOS_EDITOR_URI} ... />
79
+ ```
80
+
81
+ **Android manifest** — add `adjustResize` so the editor shrinks when the keyboard appears:
82
+
83
+ ```xml
84
+ <activity android:windowSoftInputMode="adjustResize" ... />
85
+ ```
86
+
87
+ **After upgrading** — always re-copy assets:
88
+
89
+ ```bash
90
+ cp -r node_modules/@actualwave/react-native-codeditor/src/assets/* android/app/src/main/assets/codeditor/
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Basic usage
96
+
97
+ ```tsx
98
+ import { useCallback, useRef } from 'react';
99
+ import { KeyboardAvoidingView, Platform } from 'react-native';
100
+ import CodeEditor from '@actualwave/react-native-codeditor';
101
+ import type { WebViewAPI, HistorySize } from '@actualwave/react-native-codeditor';
102
+
103
+ export default function EditorScreen() {
104
+ const apiRef = useRef<WebViewAPI | null>(null);
105
+
106
+ const handleInitialized = useCallback((api: WebViewAPI) => {
107
+ apiRef.current = api;
108
+ void api.focus(); // opens Android soft keyboard
109
+ }, []);
110
+
111
+ return (
112
+ <KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
113
+ <CodeEditor
114
+ content="const x = 42;"
115
+ language="javascript"
116
+ theme="darcula"
117
+ onInitialized={handleInitialized}
118
+ onContentUpdate={(content) => console.log(content.length)}
119
+ onHistorySizeUpdate={(size) => console.log(size.undo, size.redo)}
120
+ onLog={(...args) => console.log('[editor]', ...args)}
121
+ onError={(err) => console.error('[editor]', err)}
122
+ />
123
+ </KeyboardAvoidingView>
124
+ );
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Architecture
131
+
132
+ Two runtimes connected via DDA (Deferred Data Access) RPC over the WebView bridge:
133
+
134
+ ```
135
+ React Native (HOST) WebView (GUEST)
136
+ ────────────────── ───────────────
137
+ CodeEditor component
138
+ └─ WebViewAPI
139
+ └─ initializeHost() ◄──► initializeGuest()
140
+ api.editor.* ──────► EditorController methods
141
+ (DDA proxy) ◄────── Promise results
142
+ ```
143
+
144
+ **Out-of-band messages** (bypass DDA, sent via `ReactNativeWebView.postMessage`):
145
+
146
+ | Type | Direction | Meaning |
147
+ |---|---|---|
148
+ | `__editorReady__` | WebView→RN | Editor fully painted; `onInitialized` fires |
149
+ | `__contentChange__` | WebView→RN | Edit, debounced 300ms — carries `{ value, undo, redo }` |
150
+ | `__selectionChange__` | WebView→RN | Selection changed — carries selected text |
151
+ | `__shortcut__` | WebView→RN | Registered shortcut triggered — carries name string |
152
+ | `__editorLog__` | WebView→RN | `window.log(...)` from WebView |
153
+ | `__editorError__` | WebView→RN | `window.onerror` from WebView |
154
+
155
+ ---
156
+
157
+ ## DDA lazy mode — critical rule
158
+
159
+ DDA operates in **lazy mode**: a proxy call builds a command chain but does NOT send it until the returned value is awaited. **Every `api.editor.*` call MUST be awaited.**
160
+
161
+ ```ts
162
+ // ✅ correct
163
+ await apiRef.current?.editor?.historyUndo();
164
+
165
+ // ✅ correct — async IIFE in useEffect
166
+ void (async () => { await apiRef.current!.editor.setLanguage('python'); })();
167
+
168
+ // ❌ wrong — command is never sent
169
+ void apiRef.current?.editor.historyUndo();
170
+ apiRef.current?.editor.historyUndo();
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Props
176
+
177
+ ### Required callbacks
178
+
179
+ | Prop | Type | Description |
180
+ |---|---|---|
181
+ | `onInitialized` | `(api: WebViewAPI) => void` | Fires when editor is fully ready. Store `api` here. Call `api.focus()` for Android keyboard. |
182
+ | `onContentUpdate` | `(content: string) => void` | After edits (debounced 300ms), full document text. |
183
+ | `onHistorySizeUpdate` | `(size: HistorySize) => void` | After edits (debounced 300ms), `{ undo, redo }` depths. |
184
+ | `onLog` | `(...args: unknown[]) => void` | `window.log()` from the WebView. |
185
+ | `onError` | `(error: unknown) => void` | `window.onerror` from the WebView. |
186
+
187
+ ### Optional callbacks
188
+
189
+ | Prop | Type | Description |
190
+ |---|---|---|
191
+ | `onSelectionChange` | `(text: string) => void` | Called when selection changes; receives selected text (empty string when collapsed). |
192
+ | `onShortcut` | `(name: string) => void` | Called when a shortcut registered via `api.editor.registerShortcut()` is triggered. Receives the name string passed at registration time. |
193
+
194
+ ### Editor configuration
195
+
196
+ | Prop | Type | Default | Description |
197
+ |---|---|---|---|
198
+ | `content` | `string` | `''` | Document content. Initial value is delivered at startup; later prop changes call `setValue` if they differ from the editor's current text. |
199
+ | `language` | `string` | — | Syntax language, e.g. `'javascript'`, `'python'`. Loaded on demand. |
200
+ | `languageConfig` | `Record<string, unknown>` | — | Options passed to the language factory, e.g. `{ jsx: true, typescript: true }` for `'javascript'`. |
201
+ | `languages` | `Record<string, string>` | — | Custom language packages `{ name: packageName }` for names that don't follow `@codemirror/lang-{name}`, e.g. `{ sksl: '@actualwave/codemirror-lang-sksl' }`. Registered before the initial `language` is resolved. |
202
+ | `embeds` | `EmbedsConfig` | — | Tagged-template DSL embeddings and support extensions mixed into `'javascript'`: `{ taggedTemplates?: string[], supportExtensions?: (string \| [string, object])[] }`. |
203
+ | `extensions` | `ExtensionSpec[]` | `[]` | CM6 extension specs. |
204
+ | `theme` | `string` | — | Theme name, e.g. `'darcula'`, `'monokai'`. |
205
+ | `viewport` | `ViewportSettings` | — | `<meta name="viewport">` options. |
206
+
207
+ ### WebView / layout
208
+
209
+ | Prop | Type | Default | Description |
210
+ |---|---|---|---|
211
+ | `editorUri` | `string` | `'file:///android_asset/codeditor/editor.html'` | Override for iOS — use `new File(Paths.bundle, 'assets/codeditor/editor.html').uri` from `expo-file-system`. |
212
+ | `allowFileAccess` | `boolean` | `true` | Required for `file://` asset loading. |
213
+ | `renderBlockingView` | `() => ReactNode` | `() => <BlockingView />` | Loading overlay while editor initialises. |
214
+
215
+ ---
216
+
217
+ ## `WebViewAPI` — editor control
218
+
219
+ `api` is received in `onInitialized`. `api.editor` is a DDA proxy — all its methods return Promises.
220
+
221
+ ### Focus
222
+
223
+ ```ts
224
+ api.focus(): Promise<void>
225
+ // Also calls webView.requestFocus() for Android keyboard.
226
+ ```
227
+
228
+ ### Content
229
+
230
+ ```ts
231
+ api.editor.getValue(): Promise<string>
232
+ api.editor.setValue(value: string): Promise<void> // preserves history
233
+ api.editor.resetValue(value?: string): Promise<void> // clears history
234
+ ```
235
+
236
+ ### Language / theme / extensions
237
+
238
+ ```ts
239
+ api.editor.setLanguage(name: string, config?: Record<string, unknown>, embeds?: EmbedsConfig): Promise<void>
240
+ api.editor.registerLanguage(name: string, packageName: string): Promise<void>
241
+ // Maps a name to a package not following @codemirror/lang-{name}; applies on the next setLanguage().
242
+ // e.g. await registerLanguage('sksl', '@actualwave/codemirror-lang-sksl'); await setLanguage('sksl');
243
+ api.editor.registerTaggedTemplate(packageName: string): Promise<void>
244
+ api.editor.registerSupportExtension(packageName: string, config?: Record<string, unknown>): Promise<void>
245
+ // Both register globally for the page's lifetime ('javascript' only); re-call setLanguage('javascript') to apply.
246
+ api.editor.setTheme(themeName?: string): Promise<void> // undefined removes theme
247
+ api.editor.setExtensions(specs: ExtensionSpec[]): Promise<void>
248
+ ```
249
+
250
+ ### Cursor and selection
251
+
252
+ ```ts
253
+ api.editor.getCursor(where?: 'from' | 'to' | 'head'): Promise<CursorPosition>
254
+ // CursorPosition = { line: number, ch: number, index: number } (line is 0-based)
255
+ api.editor.setCursor(line: number, ch?: number): Promise<void>
256
+ api.editor.getSelection(): Promise<string>
257
+ api.editor.setSelection(anchor: number, head?: number): Promise<void>
258
+ api.editor.replaceSelection(text: string): Promise<void>
259
+ api.editor.cancelSelection(): Promise<void>
260
+ ```
261
+
262
+ ### History
263
+
264
+ ```ts
265
+ api.editor.historyUndo(): Promise<boolean>
266
+ api.editor.historyRedo(): Promise<boolean>
267
+ api.editor.historyClear(): Promise<void>
268
+ api.editor.historySize(): Promise<HistorySize> // { undo, redo }
269
+ ```
270
+
271
+ ### Editing commands
272
+
273
+ ```ts
274
+ api.editor.indentMore(): Promise<boolean>
275
+ api.editor.indentLess(): Promise<boolean>
276
+ api.editor.toggleComment(): Promise<boolean>
277
+ api.editor.moveLineUp(): Promise<boolean>
278
+ api.editor.moveLineDown(): Promise<boolean>
279
+ api.editor.deleteLine(): Promise<boolean>
280
+ api.editor.selectLine(): Promise<boolean>
281
+ api.editor.selectParentSyntax(): Promise<boolean>
282
+ ```
283
+
284
+ ### Autocomplete
285
+
286
+ ```ts
287
+ api.editor.startCompletion(): Promise<void>
288
+ api.editor.setCompletions(items: CompletionItem[]): Promise<void>
289
+ // CompletionItem = { label, type?, detail?, info? }
290
+ ```
291
+
292
+ ### Custom shortcuts (hardware keyboard)
293
+
294
+ Register key bindings from the React Native side. When triggered in the editor, fires `onShortcut` on the `<CodeEditor>` component with the given name. Shortcuts use `Prec.highest` priority, overriding all built-in keymaps.
295
+
296
+ ```ts
297
+ api.editor.registerShortcut(key: string, name: string): Promise<void>
298
+ api.editor.unregisterShortcut(key: string): Promise<void>
299
+ ```
300
+
301
+ Key notation: `Mod` = Cmd on macOS/iOS, Ctrl on Android/Windows. Examples: `'Mod-s'`, `'Mod-Enter'`, `'Mod-Shift-f'`, `'F5'`.
302
+
303
+ ```tsx
304
+ // Register in onInitialized, handle in onShortcut
305
+ <CodeEditor
306
+ onInitialized={async (api) => {
307
+ await api.editor.registerShortcut('Mod-s', 'save');
308
+ await api.editor.registerShortcut('Mod-Enter', 'run');
309
+ }}
310
+ onShortcut={(name) => {
311
+ if (name === 'save') handleSave();
312
+ if (name === 'run') handleRun();
313
+ }}
314
+ ...
315
+ />
316
+ ```
317
+
318
+ ### Font / keyboard / scroll / advanced
319
+
320
+ ```ts
321
+ api.editor.setFontSize(size: number): Promise<void>
322
+ api.editor.setSoftKeyboard(enabled: boolean): Promise<void>
323
+ api.editor.setViewport(options: ViewportSettings): Promise<void>
324
+ api.editor.scrollToCursor(margin?: number): Promise<void>
325
+ api.editor.loadExtension(moduleName: string): Promise<object>
326
+ api.editor.destroy(): Promise<void>
327
+ ```
328
+
329
+ ### Synchronous RN-side only
330
+
331
+ ```ts
332
+ api.injectJavaScript(code: string): void
333
+ api.requestFocus(): void
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Content model
339
+
340
+ `content` sets the initial document, and later prop changes are pushed to the editor via `setValue` — but only when they differ from the text the editor last reported, so writing `onContentUpdate` output back to `content` is a harmless no-op. Because `onContentUpdate` is debounced (300ms), avoid transforming the text and feeding it back while the user is typing.
341
+
342
+ To push content programmatically you can also use the API:
343
+
344
+ ```ts
345
+ await api.editor.setValue(newCode); // preserve history
346
+ await api.editor.resetValue(newCode); // clear history (e.g. opening new file)
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Extension specs
352
+
353
+ `ExtensionSpec` accepted by `extensions` prop and `api.editor.setExtensions()`:
354
+
355
+ | Form | Example | Behaviour |
356
+ |---|---|---|
357
+ | Package name string | `'@codemirror/search'` | Loaded via built-in registry |
358
+ | `[packageName, exportName]` | `['@uiw/codemirror-theme-nord', 'nord']` | Returns `mod[exportName]` |
359
+ | `[packageName, options]` | `['@codemirror/search', { top: true }]` | Resolver called with options |
360
+ | Pre-built extension | `myExtension` | Used as-is |
361
+
362
+ Built-in registry: `@codemirror/autocomplete`, `@codemirror/search`, `@codemirror/lint`, `@codemirror/collab`, `@codemirror/theme-one-dark`.
363
+
364
+ ---
365
+
366
+ ## Supported languages
367
+
368
+ `angular` `cpp` `css` `go` `html` `java` `javascript` `jinja` `json` `less` `lezer`
369
+ `liquid` `markdown` `php` `python` `rust` `sass` `sql` `vue` `wast` `xml` `yaml`
370
+
371
+ Bundled packages that don't follow the `@codemirror/lang-{name}` naming (e.g. `sksl` →
372
+ `@actualwave/codemirror-lang-sksl`) are not auto-detected — map them with the `languages`
373
+ prop or `api.editor.registerLanguage()` first, otherwise `setLanguage` rejects with
374
+ "No language support found".
375
+
376
+ Legacy modes (100+ more) via `loadExtension`:
377
+
378
+ ```ts
379
+ const { swift } = await api.editor.loadExtension('@codemirror/legacy-modes/mode/swift');
380
+ ```
381
+
382
+ ---
383
+
384
+ ## Themes
385
+
386
+ `androidstudio` `andromeda` `atomone` `aura` `basic` `bbedit` `copilot` `darcula`
387
+ `dracula` `duotone` `eclipse` `github` `material` `monokai` `nord` `okaidia` `solarized`
388
+ `sublime` `tokyoNight` `vscode` `xcode`
389
+
390
+ Two-word themes use camelCase: `tokyoNight`, `githubDark`, `githubLight`, `vscodeDark`, `xcodeDark`, `xcodeLight`, `solarizedDark`, `solarizedLight`.
391
+
392
+ ---
393
+
394
+ ## Built-in keyboard shortcuts
395
+
396
+ The editor ships with standard CodeMirror 6 keymaps active by default.
397
+
398
+ ### Editing (`defaultKeymap`)
399
+ | Key | Action |
400
+ |---|---|
401
+ | `Enter` | Insert newline |
402
+ | `Backspace` / `Delete` | Delete character |
403
+ | `Tab` | Indent |
404
+ | `Shift-Tab` | Unindent |
405
+ | `Mod-a` | Select all |
406
+
407
+ ### History (`historyKeymap`)
408
+ | Key | Action |
409
+ |---|---|
410
+ | `Mod-z` | Undo |
411
+ | `Mod-y` / `Mod-Shift-z` | Redo |
412
+
413
+ ### Search (`searchKeymap`)
414
+ | Key | Action |
415
+ |---|---|
416
+ | `Mod-f` | Open search panel |
417
+ | `F3` / `Mod-g` | Find next |
418
+ | `Escape` | Close search panel |
419
+
420
+ ### Code folding (`foldKeymap`)
421
+ | Key | Action |
422
+ |---|---|
423
+ | `Mod-Shift-[` | Fold at cursor |
424
+ | `Mod-Shift-]` | Unfold at cursor |
425
+
426
+ ### Autocomplete (`completionKeymap`)
427
+ | Key | Action |
428
+ |---|---|
429
+ | `Ctrl-Space` | Trigger completion |
430
+ | `Enter` / `Tab` | Accept completion |
431
+ | `Escape` | Close completion |
432
+
433
+ > On mobile, most shortcuts require a hardware keyboard. Use `api.editor.*` commands programmatically instead.
434
+
435
+ ---
436
+
437
+ ## Keyboard / layout
438
+
439
+ Wrap in `KeyboardAvoidingView` so the editor shrinks when the soft keyboard appears:
440
+
441
+ ```tsx
442
+ <KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
443
+ <CodeEditor ... />
444
+ </KeyboardAvoidingView>
445
+ ```
446
+
447
+ Call `api.focus()` inside `onInitialized` to trigger the Android soft keyboard immediately.
448
+
449
+ ---
450
+
451
+ ## Common pitfalls
452
+
453
+ **DDA calls not dispatched** — forgetting `await` silently does nothing. Every `api.editor.*` must be awaited.
454
+
455
+ **`onInitialized` timing** — `api` is not available until this fires. Guard all API calls with `if (!apiRef.current) return`.
456
+
457
+ **Content updates are debounced** — `onContentUpdate` fires 300ms after the last edit, so `content` may briefly lag behind the editor. Don't rewrite `content` with modified text mid-typing.
458
+
459
+ **`setLanguage` rejects for unregistered names** — custom packages like `sksl` must be registered via the `languages` prop or `registerLanguage()` first.
460
+
461
+ **Android assets not copied** — if the WebView shows "Error loading page", the `src/assets/` files haven't been copied to `android/app/src/main/assets/codeditor/`. Re-run the copy command.
462
+
463
+ **iOS URI** — the default `editorUri` is Android-only. iOS requires `new File(Paths.bundle, 'assets/codeditor/editor.html').uri` from `expo-file-system` (SDK 54+ API; on older SDKs use `FileSystem.bundleDirectory`).
464
+
465
+ **Upgrading the library** — always re-copy assets after upgrading:
466
+
467
+ ```bash
468
+ cp -r node_modules/@actualwave/react-native-codeditor/src/assets/* android/app/src/main/assets/codeditor/
469
+ ```
@@ -0,0 +1,120 @@
1
+ THIRD PARTY NOTICES
2
+ ===================
3
+
4
+ This package distributes compiled browser assets built from the following
5
+ open-source libraries. Their licenses and copyright notices are reproduced
6
+ below as required by the MIT License.
7
+
8
+
9
+ -------------------------------------------------------------------------------
10
+ CodeMirror, @codemirror/*, @lezer/*, crelt, style-mod, w3c-keyname,
11
+ @marijn/find-cluster-break
12
+ -------------------------------------------------------------------------------
13
+ MIT License
14
+
15
+ Copyright (C) 2018-2024 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ of this software and associated documentation files (the "Software"), to deal
19
+ in the Software without restriction, including without limitation the rights
20
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ copies of the Software, and to permit persons to whom the Software is
22
+ furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in all
25
+ copies or substantial portions of the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ SOFTWARE.
34
+
35
+ https://codemirror.net/
36
+
37
+
38
+ -------------------------------------------------------------------------------
39
+ @uiw/codemirror-themes, @uiw/codemirror-theme-*
40
+ -------------------------------------------------------------------------------
41
+ MIT License
42
+
43
+ Copyright (c) 2022 kenny wong <wowohoo@qq.com>
44
+
45
+ Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ of this software and associated documentation files (the "Software"), to deal
47
+ in the Software without restriction, including without limitation the rights
48
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
+ copies of the Software, and to permit persons to whom the Software is
50
+ furnished to do so, subject to the following conditions:
51
+
52
+ The above copyright notice and this permission notice shall be included in all
53
+ copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
61
+ SOFTWARE.
62
+
63
+ https://github.com/uiwjs/react-codemirror
64
+
65
+
66
+ -------------------------------------------------------------------------------
67
+ cm6-graphql, graphql, graphql-language-service
68
+ -------------------------------------------------------------------------------
69
+ MIT License
70
+
71
+ Copyright (c) 2021 GraphQL Contributors
72
+
73
+ Permission is hereby granted, free of charge, to any person obtaining a copy
74
+ of this software and associated documentation files (the "Software"), to deal
75
+ in the Software without restriction, including without limitation the rights
76
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
77
+ copies of the Software, and to permit persons to whom the Software is
78
+ furnished to do so, subject to the following conditions:
79
+
80
+ The above copyright notice and this permission notice shall be included in all
81
+ copies or substantial portions of the Software.
82
+
83
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
84
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
85
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
86
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
87
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
88
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
89
+ SOFTWARE.
90
+
91
+ https://github.com/graphql/graphiql
92
+ https://github.com/graphql/graphql-js
93
+
94
+
95
+ -------------------------------------------------------------------------------
96
+ @babel/runtime
97
+ -------------------------------------------------------------------------------
98
+ MIT License
99
+
100
+ Copyright (c) 2014-present Sebastian McKenzie and other contributors
101
+
102
+ Permission is hereby granted, free of charge, to any person obtaining a copy
103
+ of this software and associated documentation files (the "Software"), to deal
104
+ in the Software without restriction, including without limitation the rights
105
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
106
+ copies of the Software, and to permit persons to whom the Software is
107
+ furnished to do so, subject to the following conditions:
108
+
109
+ The above copyright notice and this permission notice shall be included in all
110
+ copies or substantial portions of the Software.
111
+
112
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
113
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
114
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
115
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
116
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
117
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
118
+ SOFTWARE.
119
+
120
+ https://babel.dev
package/app.plugin.js CHANGED
@@ -1,4 +1,4 @@
1
- const { withDangerousMod, withXcodeProject } = require("@expo/config-plugins");
1
+ const { withDangerousMod, withXcodeProject } = require("expo/config-plugins");
2
2
  const fs = require("fs");
3
3
  const path = require("path");
4
4