@aardarch/aardink-web 0.6.0-rc1 → 0.6.0-rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,6 +44,18 @@ const savedAt = editor.getAlternativeVersionId(); // unsaved while it differs
44
44
  editor.dispose();
45
45
  ```
46
46
 
47
+ `setValue` is for opening a file: it clears the undo history. A change the user should be able to
48
+ undo, such as an assistant's rewrite, goes through `replaceValue` (the whole text) or Monaco's
49
+ `executeEdits` (ranges). Either is one undo step that keeps the history before it, and changes
50
+ only what differs, so carets and folds in unchanged text stay put:
51
+
52
+ ```ts
53
+ editor.replaceValue(rewritten); // undo() brings the old text back
54
+ editor.executeEdits('assistant', [
55
+ { range: { startLineNumber: 3, startColumn: 1, endLineNumber: 3, endColumn: 9 }, text: '<button/>' },
56
+ ]);
57
+ ```
58
+
47
59
  A language of your own is a Monarch grammar registered before use, optionally extending a built-in
48
60
  language's completions, diagnostics and folding, with Monaco's `defineTheme` for its colours:
49
61
 
@@ -52,14 +64,24 @@ import { defineTheme, registerLanguage } from '@aardarch/aardink-web';
52
64
 
53
65
  await registerLanguage(
54
66
  { id: 'toy', extends: 'xml', grammar: { tokenizer: { root: [[/\bshout\b/, 'keyword']] } } },
55
- { provideCompletionItems: (text, line, column) => [{ label: 'shout', kind: 'element' }] },
67
+ {
68
+ triggerCharacters: ['{'], // besides XML's
69
+ provideCompletionItems: (text, line, column) => [{ label: 'shout', kind: 'element' }],
70
+ },
56
71
  );
57
72
  await defineTheme('toy-dark', { base: 'vs-dark', inherit: true, rules: [{ token: 'keyword', foreground: 'ff00ff' }] });
58
73
  ```
59
74
 
75
+ Completion items take Monaco's `filterText`, `sortText` and `range` too, and
76
+ `inheritCompletions: false` in the definition leaves out the extended language's completions
77
+ (XML's are Android-flavoured) while keeping its diagnostics and folding. A hover can carry an
78
+ `example`, shown as code.
79
+
60
80
  The editor fills its container, so give the container a size. `createEditor` is async because
61
81
  the first call loads the WebAssembly module (about 13 MB, 4.7 MB gzipped); every editor on the
62
- page shares that one module. See [`index.d.ts`](./index.d.ts) for the full API, and the
82
+ page shares that one module. If that load fails, the call rejects and the next call loads again
83
+ (though Chrome keeps a failed module download until the page is reloaded). See
84
+ [`index.d.ts`](./index.d.ts) for the full API, and the
63
85
  [integration guide](https://github.com/aardarch/aardink/blob/main/docs/WEB_INTEGRATION.md) for how
64
86
  Monaco's options and calls map onto it.
65
87
 
@@ -102,9 +124,7 @@ the measurements and the device checklist.
102
124
  - **A disposed editor is not fully released** (about 275 KB each) until Aardink moves to Compose
103
125
  Multiplatform 1.13. Reuse one editor with `setValue` and `updateOptions` rather than mounting
104
126
  one per view.
105
- - Themes are colours only: bold and italic in theme rules are ignored.
106
- - Whitespace is not rendered (`renderWhitespace`), and a completion inserts plain text: snippet
107
- placeholders such as `$1` are not expanded.
127
+ - A theme rule's `background` is ignored; its `foreground` and `fontStyle` apply.
108
128
 
109
129
  ## Licence
110
130
 
package/index.d.ts CHANGED
@@ -35,6 +35,8 @@ export interface AardinkOptions {
35
35
  insertSpaces?: boolean;
36
36
  /** Monaco's `renderLineHighlight`: anything but `'none'` highlights each caret's line. */
37
37
  renderLineHighlight?: 'none' | 'line' | 'gutter' | 'all';
38
+ /** Which spaces and tabs are drawn, as dots and arrows. `'selection'` by default. */
39
+ renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
38
40
  /** Colours brackets by nesting depth. On by default. */
39
41
  bracketPairColorization?: { enabled?: boolean } | boolean;
40
42
  /** A picture of the whole text at the side, with a slider over what is shown. Off by default. */
@@ -70,14 +72,49 @@ export interface AardinkContentChange {
70
72
  versionId: number;
71
73
  isUndoing: boolean;
72
74
  isRedoing: boolean;
73
- /** The whole text was replaced (`setValue`). */
75
+ /** The whole text was replaced and the undo history cleared (`setValue`); `false` for `replaceValue` and `executeEdits`. */
74
76
  isFlush: boolean;
75
77
  }
76
78
 
79
+ /**
80
+ * Monaco's `IIdentifiedSingleEditOperation`, for `executeEdits`: replaces `range` with `text`.
81
+ * `null` or `''` deletes the range; an empty range inserts. A position past the end of its line is
82
+ * the line's end, and one past the last line the end of the text, as Monaco validates them.
83
+ */
84
+ export interface AardinkEditOperation {
85
+ range: AardinkRange;
86
+ text: string | null;
87
+ /** Accepted for Monaco's shape, and ignored. */
88
+ forceMoveMarkers?: boolean;
89
+ }
90
+
77
91
  export interface AardinkEditor {
78
92
  getValue(): string;
79
- /** Replaces the whole text and clears undo history. Fires the change listeners. */
93
+ /**
94
+ * Replaces the whole text and clears undo history, as when a file is opened. Fires the change
95
+ * listeners with `isFlush: true`. For a change the user should be able to undo, use
96
+ * `replaceValue` or `executeEdits`.
97
+ */
80
98
  setValue(text: string): void;
99
+ /**
100
+ * Replaces the whole text as one undo step, keeping the history before it: for a rewrite the user
101
+ * should be able to undo, such as an assistant's. Only what differs changes (lines compared, then
102
+ * characters), so carets, folds and diagnostics in unchanged text stay where they are. The change
103
+ * listeners get it with `isFlush: false` and a new `versionId`; `undo()` brings the old text back,
104
+ * and `getAlternativeVersionId()` its value then. Works in a read-only editor, as `setValue` does.
105
+ * Returns whether the text changed.
106
+ */
107
+ replaceValue(text: string): boolean;
108
+ /**
109
+ * Monaco's `executeEdits`: applies `edits` (which must not overlap) as one undo step, keeping the
110
+ * history, each reduced to the characters it really changes so carets and folds elsewhere stay
111
+ * put. Then selects `endCursorState` when given (positions in the text after the edits, as in
112
+ * Monaco), else carries the selections through the edits;
113
+ * a cursor-state computer function is not called. `source` is accepted for Monaco's shape.
114
+ * Returns `false`, changing nothing, in a read-only editor, as Monaco does; throws for edits that
115
+ * overlap. Reported to the change listeners as for `replaceValue`.
116
+ */
117
+ executeEdits(source: string | null | undefined, edits: AardinkEditOperation[], endCursorState?: AardinkSelection[] | ((...args: unknown[]) => unknown)): boolean;
81
118
  updateOptions(options: Partial<AardinkOptions>): void;
82
119
  /** Full text after every change, at most once per frame, and what the change was. Returns an unsubscribe function. */
83
120
  onDidChangeContent(listener: (text: string, change: AardinkContentChange) => void): () => void;
@@ -90,11 +127,24 @@ export interface AardinkEditor {
90
127
  setDiagnostics(diagnostics: AardinkDiagnostic[] | null): void;
91
128
  /**
92
129
  * The language's own diagnostics each time they are collected: 500 ms after the editor appears,
93
- * and after each pause in typing. Not called while a list from `setDiagnostics` is shown.
130
+ * after each pause in typing, and on `revalidate()`. Not called while a list from
131
+ * `setDiagnostics` is shown.
94
132
  * Returns an unsubscribe function.
95
133
  */
96
134
  onDidChangeDiagnostics(listener: (diagnostics: AardinkDiagnostic[]) => void): () => void;
135
+ /**
136
+ * Collects the language's own diagnostics again now, without waiting for an edit: for when what
137
+ * your `provideDiagnostics` depends on outside the text has changed (another file, a setting).
138
+ * They reach `onDidChangeDiagnostics` as usual. Does nothing while a list from `setDiagnostics`
139
+ * is shown.
140
+ */
141
+ revalidate(): void;
97
142
  revealPosition(line: number, column: number): void;
143
+ /**
144
+ * Opens the find panel and moves the keyboard focus to its find field, from wherever on the
145
+ * page it was. Enter goes to the next match, Shift+Enter to the previous one, and Escape closes
146
+ * the panel and gives the focus back to the text.
147
+ */
98
148
  showFind(): void;
99
149
  undo(): boolean;
100
150
  redo(): boolean;
@@ -131,29 +181,104 @@ export interface AardinkLanguageDefinition {
131
181
  grammar: object;
132
182
  /** A built-in or registered language whose completions, diagnostics, hover and folding this one takes too, e.g. `'xml'`. */
133
183
  extends?: string;
184
+ /**
185
+ * With `extends`: `false` leaves out that language's completions (and, when the providers give
186
+ * `triggerCharacters`, its trigger characters), keeping its diagnostics, hover, folding and the
187
+ * rest. `true` by default. To leave them out for one request only, answer with
188
+ * `{ suggestions, exclusive: true }`.
189
+ */
190
+ inheritCompletions?: boolean;
134
191
  displayName?: string;
135
192
  extensions?: string[];
136
193
  /** As in Monaco's language configuration: what Ctrl/Cmd+/ comments with. */
137
194
  comments?: { lineComment?: string; blockComment?: [string, string] };
138
195
  }
139
196
 
197
+ /** Monaco's flags for a completion's `insertText`. */
198
+ export declare const CompletionItemInsertTextRule: {
199
+ readonly None: 0;
200
+ /** Insert the snippet's whitespace as written, rather than indented as the line it lands on. */
201
+ readonly KeepWhitespace: 1;
202
+ /** `insertText` is a snippet: `$1`, `${1:placeholder}` and `${1|a,b|}` are tab stops, `$0` the final caret. */
203
+ readonly InsertAsSnippet: 4;
204
+ };
205
+
206
+ /** Monaco's `IRange`: 1-based lines and columns, `endColumn` exclusive. */
207
+ export interface AardinkRange {
208
+ startLineNumber: number;
209
+ startColumn: number;
210
+ endLineNumber: number;
211
+ endColumn: number;
212
+ }
213
+
140
214
  export interface AardinkCompletionItem {
141
215
  label: string;
142
- /** What accepting it types; the label when absent. */
216
+ /** What accepting it types; the label when absent. A snippet with `InsertAsSnippet`. */
143
217
  insertText?: string;
144
- kind?: 'element' | 'attribute' | 'value' | 'snippet' | 'module' | 'property';
218
+ /** `CompletionItemInsertTextRule` flags, as in Monaco. */
219
+ insertTextRules?: number;
220
+ /**
221
+ * The icon. `'function'` is another name for `'transform'`, and `'color'` for `'colorRef'`, as
222
+ * Monaco calls them; any other name shows as `'value'`.
223
+ */
224
+ kind?: 'element' | 'attribute' | 'value' | 'snippet' | 'module' | 'property' | 'transform' | 'function' | 'colorRef' | 'color';
225
+ /** Shown beside the label when there is no `documentation`. */
145
226
  detail?: string;
146
- documentation?: string;
227
+ /** Shown beside the label; Monaco's `{ value }` is shown as plain text. */
228
+ documentation?: string | { value: string };
229
+ /**
230
+ * What the text typed so far is matched against, as in Monaco: its characters in order, ignoring
231
+ * case, the first at the start of `filterText` or of a word in it. Typed so far is the text from
232
+ * the start of what the item replaces to the caret. Without it the item is not filtered: your
233
+ * provider is asked again on each letter typed, and offers what fits.
234
+ */
235
+ filterText?: string;
236
+ /** When any item has one, your items are ordered by it (by `label` where it is missing), as in Monaco. */
237
+ sortText?: string;
238
+ /**
239
+ * The text accepting the item replaces, which must contain the caret, as in Monaco. Of
240
+ * `{ insert, replace }`, `replace` is used. Without it the item replaces the word before the
241
+ * caret, back to the first of `< > { } ( ) [ ] " ' = , ; . @ | :` or whitespace.
242
+ */
243
+ range?: AardinkRange | { insert: AardinkRange; replace: AardinkRange };
244
+ }
245
+
246
+ /** Monaco's `CompletionList`, plus `exclusive`: `true` leaves out the extended language's completions for this request. */
247
+ export interface AardinkCompletionList {
248
+ suggestions: AardinkCompletionItem[];
249
+ exclusive?: boolean;
250
+ /** Accepted for Monaco's shape, and ignored: your provider is asked again on each letter typed anyway. */
251
+ incomplete?: boolean;
252
+ }
253
+
254
+ export interface AardinkHover {
255
+ title?: string;
256
+ /** Plain text. */
257
+ contents: string;
258
+ /** Shown as code below `contents`. */
259
+ example?: string;
147
260
  }
148
261
 
149
262
  /**
150
263
  * What a registered language knows beyond its grammar. Each gets the whole text and, where it
151
264
  * asks about a place, a 1-based line and column; each may answer at once or with a Promise. With
152
- * `extends`, the built-in language's answers come after these.
265
+ * `extends`, the built-in language's answers come after these, less any completion with the same
266
+ * `kind` and `label` as one of yours (see `inheritCompletions` to leave them all out).
153
267
  */
154
268
  export interface AardinkLanguageProviders {
155
- provideCompletionItems?(text: string, line: number, column: number): AardinkCompletionItem[] | null | Promise<AardinkCompletionItem[] | null>;
156
- provideHover?(text: string, line: number, column: number): { title?: string; contents: string } | null | Promise<{ title?: string; contents: string } | null>;
269
+ /**
270
+ * Characters that open the completion list when typed, as on Monaco's completion provider, e.g.
271
+ * `['{', '|', '@', '$']`. With `extends` they add to that language's (`'xml'`: `< / space : " =`),
272
+ * or replace them with `inheritCompletions: false`; without, that language's apply. Letters and
273
+ * digits always ask again while the list is open.
274
+ */
275
+ triggerCharacters?: string[];
276
+ provideCompletionItems?(
277
+ text: string,
278
+ line: number,
279
+ column: number,
280
+ ): AardinkCompletionItem[] | AardinkCompletionList | null | Promise<AardinkCompletionItem[] | AardinkCompletionList | null>;
281
+ provideHover?(text: string, line: number, column: number): AardinkHover | null | Promise<AardinkHover | null>;
157
282
  provideDiagnostics?(text: string): AardinkDiagnostic[] | Promise<AardinkDiagnostic[]>;
158
283
  }
159
284
 
@@ -161,9 +286,10 @@ export interface AardinkLanguageProviders {
161
286
  export function registerLanguage(definition: AardinkLanguageDefinition, providers?: AardinkLanguageProviders): Promise<void>;
162
287
 
163
288
  /**
164
- * Monaco's `defineTheme` data. Token rules name a grammar's tokens; `tag` also colours
165
- * `tag.aardflex`. Themes are colours only: a rule's `fontStyle` and `background` are accepted, so
166
- * Monaco theme data passes as it is, and ignored.
289
+ * Monaco's `defineTheme` data. Token rules name tokens as Monaco does, and the longest matching
290
+ * prefix wins: `tag` also colours `tag.aardflex`, `comment.doc` only documentation comments. A
291
+ * rule's `fontStyle` (`'bold'`, `'italic'`, `'underline'`, `'strikethrough'`, or `''` for none)
292
+ * applies too; its `background` is accepted, so Monaco theme data passes as it is, and ignored.
167
293
  */
168
294
  export interface AardinkThemeData {
169
295
  base: 'vs' | 'vs-dark' | 'hc-black' | 'hc-light';
@@ -191,7 +317,12 @@ export function createEditor(
191
317
  /** For debugging a grammar: the tokens of `text` in `languageId`, per line, as Monaco's `tokenize` gives them. */
192
318
  export function tokenize(text: string, languageId: string): Promise<{ offset: number; type: string }[][]>;
193
319
 
194
- /** Starts loading the WebAssembly module without mounting anything. */
320
+ /**
321
+ * Starts loading the WebAssembly module without mounting anything. Every call shares one load.
322
+ * When it fails (a network error, say), this and every call waiting on it reject, and the next
323
+ * call of any function here starts a new load. A browser may still hold on to a module whose
324
+ * download failed until the page is reloaded (Chrome does), so that new load can fail the same way.
325
+ */
195
326
  export function preloadAardink(): Promise<void>;
196
327
 
197
328
  /** The Aardink version this package was built from. */
package/index.js CHANGED
@@ -17,20 +17,30 @@
17
17
  // Adapts the Kotlin module's integer-handle exports (aardinkCreate, aardinkGetValue, ...) into
18
18
  // the Monaco-shaped object described in index.d.ts.
19
19
 
20
- export const version = '0.6.0-rc1';
20
+ export const version = '0.6.0-rc3';
21
+
22
+ /** Monaco's flags for a completion's `insertText`. */
23
+ export const CompletionItemInsertTextRule = Object.freeze({ None: 0, KeepWhitespace: 1, InsertAsSnippet: 4 });
21
24
 
22
25
  let kotlinModule;
23
26
 
24
27
  function load() {
25
- // Memoised: every editor on the page shares one WebAssembly instance.
26
- kotlinModule ??= import('./kotlin/aardink-web.mjs').then((k) => {
27
- // Compose looks for resources relative to the page, not this package. A literal
28
- // new URL(..., import.meta.url) is also what makes a bundler (Vite) emit the font file.
29
- k.aardinkSetBundledFontUrl(
30
- new URL('./kotlin/composeResources/com.aardarch.aardink.web.res/font/jetbrains_mono_regular.ttf', import.meta.url).href,
31
- );
32
- return k;
33
- });
28
+ // Memoised: every editor on the page shares one WebAssembly instance. A failed load is
29
+ // forgotten, so the next call tries again rather than repeating one network blip for the
30
+ // page's life.
31
+ kotlinModule ??= import('./kotlin/aardink-web.mjs')
32
+ .then((k) => {
33
+ // Compose looks for resources relative to the page, not this package. A literal
34
+ // new URL(..., import.meta.url) is also what makes a bundler (Vite) emit the font file.
35
+ k.aardinkSetBundledFontUrl(
36
+ new URL('./kotlin/composeResources/com.aardarch.aardink.web.res/font/jetbrains_mono_regular.ttf', import.meta.url).href,
37
+ );
38
+ return k;
39
+ })
40
+ .catch((error) => {
41
+ kotlinModule = undefined;
42
+ throw error;
43
+ });
34
44
  return kotlinModule;
35
45
  }
36
46
 
@@ -54,6 +64,25 @@ function withRange(s) {
54
64
  };
55
65
  }
56
66
 
67
+ /** The fields of a Monaco `ISelection` the Kotlin side reads. */
68
+ function toKotlinSelection(s) {
69
+ return {
70
+ selectionStartLineNumber: s.selectionStartLineNumber,
71
+ selectionStartColumn: s.selectionStartColumn,
72
+ positionLineNumber: s.positionLineNumber,
73
+ positionColumn: s.positionColumn,
74
+ };
75
+ }
76
+
77
+ /** The fields of a Monaco edit operation the Kotlin side reads; a Monaco `Range` is a class, so copy them. */
78
+ function toKotlinEdit(edit) {
79
+ const r = edit.range;
80
+ return {
81
+ range: { startLineNumber: r.startLineNumber, startColumn: r.startColumn, endLineNumber: r.endLineNumber, endColumn: r.endColumn },
82
+ text: edit.text ?? null,
83
+ };
84
+ }
85
+
57
86
  /** For debugging a grammar: the tokens of `text` in `languageId`, per line, as Monaco's tokenize gives them. */
58
87
  export async function tokenize(text, languageId) {
59
88
  const k = await load();
@@ -95,6 +124,9 @@ export async function registerLanguage(definition, providers = {}) {
95
124
  extends: definition.extends,
96
125
  displayName: definition.displayName,
97
126
  extensions: definition.extensions,
127
+ inheritCompletions: definition.inheritCompletions,
128
+ // On the providers, as on Monaco's completion provider; the Kotlin side reads it with the definition.
129
+ triggerCharacters: providers.triggerCharacters,
98
130
  grammar,
99
131
  }),
100
132
  (text, line, column) => answer(providers.provideCompletionItems, text, line, column),
@@ -112,9 +144,16 @@ function toVsCodeTheme(theme) {
112
144
  type: base === 'vscode-light' ? 'light' : 'dark',
113
145
  base: theme.inherit === false ? undefined : base,
114
146
  colors: theme.colors ?? {},
147
+ // A rule's colour and font style; its background is not drawn.
115
148
  tokenColors: theme.rules
116
- .filter((rule) => rule.foreground)
117
- .map((rule) => ({ scope: rule.token, settings: { foreground: `#${rule.foreground.replace(/^#/, '')}` } })),
149
+ .filter((rule) => rule.foreground || rule.fontStyle !== undefined)
150
+ .map((rule) => ({
151
+ scope: rule.token,
152
+ settings: {
153
+ ...(rule.foreground ? { foreground: `#${rule.foreground.replace(/^#/, '')}` } : {}),
154
+ ...(rule.fontStyle !== undefined ? { fontStyle: rule.fontStyle } : {}),
155
+ },
156
+ })),
118
157
  };
119
158
  }
120
159
 
@@ -134,7 +173,7 @@ export const defineTheme = registerTheme;
134
173
  */
135
174
  function toKotlinOptions(options) {
136
175
  const out = {};
137
- for (const key of ['language', 'theme', 'fontSize', 'readOnly', 'showGutter', 'showLineNumbers', 'showFoldMarkers', 'tabSize', 'insertSpaces', 'highlightCurrentLine']) {
176
+ for (const key of ['language', 'theme', 'fontSize', 'readOnly', 'showGutter', 'showLineNumbers', 'showFoldMarkers', 'tabSize', 'insertSpaces', 'highlightCurrentLine', 'renderWhitespace']) {
138
177
  if (options[key] !== undefined) out[key] = options[key];
139
178
  }
140
179
  if (options.wordWrap !== undefined) out.wordWrap = options.wordWrap === 'on';
@@ -172,6 +211,15 @@ export async function createEditor(container, onChange, options = {}) {
172
211
  return {
173
212
  getValue: () => k.aardinkGetValue(id),
174
213
  setValue: (text) => k.aardinkSetValue(id, text),
214
+ replaceValue: (text) => k.aardinkReplaceValue(id, text),
215
+ executeEdits(source, edits, endCursorState) {
216
+ // `source` only names the edit in Monaco; a cursor-state computer function is not called.
217
+ const selections = Array.isArray(endCursorState) && endCursorState.length ? endCursorState.map(toKotlinSelection) : null;
218
+ const result = k.aardinkExecuteEdits(id, JSON.stringify(edits.map(toKotlinEdit)), JSON.stringify(selections));
219
+ if (result === 'read-only') return false;
220
+ if (result) throw new Error(`Aardink: ${result}`);
221
+ return true;
222
+ },
175
223
  updateOptions: (patch) => k.aardinkUpdateOptions(id, JSON.stringify(toKotlinOptions(patch))),
176
224
  onDidChangeContent(listener) {
177
225
  contentListeners.add(listener);
@@ -186,21 +234,13 @@ export async function createEditor(container, onChange, options = {}) {
186
234
  diagnosticsListeners.add(listener);
187
235
  return () => diagnosticsListeners.delete(listener);
188
236
  },
237
+ revalidate: () => k.aardinkRevalidate(id),
189
238
  revealPosition: (line, column) => k.aardinkRevealPosition(id, line, column),
190
239
  setBaseline: (text) => k.aardinkSetBaseline(id, text ?? ''),
191
240
  format: () => new Promise((resolve) => k.aardinkFormat(id, resolve)),
192
241
  focus: () => k.aardinkFocus(id),
193
242
  getSelections: () => JSON.parse(k.aardinkGetSelections(id)).map(withRange),
194
- setSelections: (selections) =>
195
- k.aardinkSetSelections(
196
- id,
197
- JSON.stringify(selections.map((s) => ({
198
- selectionStartLineNumber: s.selectionStartLineNumber,
199
- selectionStartColumn: s.selectionStartColumn,
200
- positionLineNumber: s.positionLineNumber,
201
- positionColumn: s.positionColumn,
202
- }))),
203
- ),
243
+ setSelections: (selections) => k.aardinkSetSelections(id, JSON.stringify(selections.map(toKotlinSelection))),
204
244
  canUndo: () => k.aardinkCanUndo(id),
205
245
  canRedo: () => k.aardinkCanRedo(id),
206
246
  pushUndoStop: () => k.aardinkPushUndoStop(id),
@@ -561,6 +561,23 @@ const js_code = {
561
561
  'androidx.compose.material3.internal.set_$external_fun' : (_this, p0, p1) => _this.set(p0, p1),
562
562
  'androidx.compose.material3.internal.get_$external_fun' : (_this, p0) => _this.get(p0),
563
563
  'com.aardarch.aardink.platform.readClipboardText' : () => navigator.clipboard.readText(),
564
+ 'com.aardarch.aardink.web.followSize' : (element) => {
565
+ let last = element.clientWidth + 'x' + element.clientHeight;
566
+ let frame = 0;
567
+ const observer = new ResizeObserver(() => {
568
+ const size = element.clientWidth + 'x' + element.clientHeight;
569
+ if (size === last) return;
570
+ last = size;
571
+ cancelAnimationFrame(frame);
572
+ frame = requestAnimationFrame(() => window.dispatchEvent(new Event('resize')));
573
+ });
574
+ observer.observe(element);
575
+ return () => {
576
+ cancelAnimationFrame(frame);
577
+ observer.disconnect();
578
+ };
579
+ },
580
+ 'com.aardarch.aardink.web.callStop' : (stop) => stop(),
564
581
  'com.aardarch.aardink.sampleweb.__callJsClosure_((String)->Unit)' : (f, p0) => f(p0),
565
582
  'com.aardarch.aardink.sampleweb.__callJsClosure_((Int,Int)->Unit)' : (f, p0, p1) => f(p0, p1),
566
583
  'com.aardarch.aardink.sampleweb.__callJsClosure_((String,Int,Int)->Js)' : (f, p0, p1, p2) => f(p0, p1, p2),
@@ -81,11 +81,14 @@ export const {
81
81
  aardinkCreate,
82
82
  aardinkGetValue,
83
83
  aardinkSetValue,
84
+ aardinkReplaceValue,
85
+ aardinkExecuteEdits,
84
86
  aardinkUpdateOptions,
85
87
  aardinkOnChange,
86
88
  aardinkOnCursorChange,
87
89
  aardinkSetDiagnostics,
88
90
  aardinkOnDiagnosticsChange,
91
+ aardinkRevalidate,
89
92
  aardinkRegisterLanguage,
90
93
  aardinkRegisterTheme,
91
94
  aardinkOnContentChange,
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aardarch/aardink-web",
3
- "version": "0.6.0-rc1",
3
+ "version": "0.6.0-rc3",
4
4
  "description": "The Aardink code editor for the browser: Compose Multiplatform on WebAssembly behind a Monaco-shaped API.",
5
5
  "keywords": [
6
6
  "code-editor",