svedit 0.3.0 → 0.4.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.
@@ -67,7 +67,7 @@ export default class Transaction {
67
67
  * @example
68
68
  * ```js
69
69
  * tr.set(["list_1", "list_items"], [1, 2, 3]);
70
- * tr.set(["page_1", "body", "0", "description"], ["Hello world", []]);
70
+ * tr.set(["page_1", "body", "0", "description"], {text: "Hello world", annotations: []});
71
71
  * ```
72
72
  */
73
73
  set (path, value) {
@@ -152,10 +152,10 @@ export default class Transaction {
152
152
  *
153
153
  * @param {Selection} selection - The new selection object
154
154
  * @returns {Transaction} This transaction instance for method chaining
155
- * @todo Check if selection is valid and throw error if not
155
+ * @throws {Error} Throws if the selection is invalid or out of bounds
156
156
  */
157
157
  set_selection(selection) {
158
- // TODO: Check if selection is valid and throw error if not
158
+ this.doc._validate_selection(selection);
159
159
  this.doc.selection = selection;
160
160
  return this;
161
161
  }
@@ -168,7 +168,7 @@ export default class Transaction {
168
168
  * when conflicting types are applied.
169
169
  *
170
170
  * @param {any} annotation_type - The type of annotation (e.g., 'link', 'bold', 'italic')
171
- * @param {any} annotation_data - Additional data for the annotation (e.g., href for links)
171
+ * @param {any} annotation_properties - Additional data for the annotation (e.g., href for links)
172
172
  * @returns {Transaction} This transaction instance for method chaining
173
173
  *
174
174
  * @example
@@ -180,64 +180,25 @@ export default class Transaction {
180
180
  * tr.annotate_text('emphasis', {});
181
181
  * ```
182
182
  */
183
- annotate_text(annotation_type, annotation_data) {
183
+ annotate_text(annotation_type, annotation_properties) {
184
184
  if (this.doc.selection.type !== 'text') return this;
185
185
 
186
186
  const { start, end } = this.doc.get_selection_range();
187
- const annotated_string = structuredClone($state.snapshot(this.doc.get(this.doc.selection.path)));
188
- const annotations = annotated_string[1];
189
- const existing_annotations = this.doc.active_annotation();
190
-
191
- // Special annotation type handling should probably be done in a separate function.
192
- // The goal is to keep the core logic simple and allow developer to extend and pick only what they need.
193
- // It could also be abstracted to not check for type (e.g. "link") but for a special attribute
194
- // e.g. "zero-range-updatable" for annotations that are updatable without a range selection change.
195
-
196
- // Special handling for links when there's no selection range
197
- // Links should be updatable by just clicking on them without a range selection
198
- if (annotation_type === 'link' && start === end && existing_annotations) {
199
-
200
- // Use findIndex for deep comparison of annotation properties (comparison of annotation properties rather than object reference via indexOf)
201
- const index = annotations.findIndex(/** @param {any} anno */ (anno) =>
202
- anno[0] === existing_annotations[0] &&
203
- anno[1] === existing_annotations[1] &&
204
- anno[2] === existing_annotations[2]
205
- );
206
- // const index = annotations.indexOf(existing_annotations);
207
-
208
- if (index !== -1) {
209
- if (annotation_data.href === '') {
210
- // Remove the annotation if the href is empty
211
- annotations.splice(index, 1);
212
- } else {
213
- annotations[index] = [
214
- existing_annotations[0],
215
- existing_annotations[1],
216
- 'link',
217
- { ...existing_annotations[3], ...annotation_data }
218
- ];
219
- }
220
-
221
- this.set(this.doc.selection.path, annotated_string);
222
- return this;
223
- }
224
- }
225
-
226
- // Regular annotation handling
227
- if (start === end) {
228
- // For non-link annotations: You can not annotate text if the selection is collapsed.
229
- return this;
230
- }
187
+ const annotated_text = structuredClone($state.snapshot(this.doc.get(this.doc.selection.path)));
188
+ const annotations = annotated_text.annotations;
189
+ const existing_annotation = this.doc.active_annotation();
190
+ const existing_annotation_same_type = this.doc.active_annotation(annotation_type);
231
191
 
232
- if (existing_annotations) {
192
+ if (existing_annotation) {
233
193
  // If there's an existing annotation of the same type, remove it
234
- if (existing_annotations[2] === annotation_type) {
194
+ if (existing_annotation_same_type) {
235
195
  const index = annotations.findIndex(/** @param {any} anno */ (anno) =>
236
- anno[0] === existing_annotations[0] &&
237
- anno[1] === existing_annotations[1] &&
238
- anno[2] === existing_annotations[2]
196
+ anno.start_offset === existing_annotation.start_offset &&
197
+ anno.end_offset === existing_annotation.end_offset
239
198
  );
240
199
  if (index !== -1) {
200
+ // Remove the annotation node from the graph
201
+ this.delete(annotations[index].node_id);
241
202
  annotations.splice(index, 1);
242
203
  }
243
204
  } else {
@@ -245,14 +206,23 @@ export default class Transaction {
245
206
  return this;
246
207
  }
247
208
  } else {
209
+ if (!this.doc.available_annotation_types.includes(annotation_type)) {
210
+ console.log(`Annotation type ${annotation_type} is not allowed here.`);
211
+ return this;
212
+ }
213
+
214
+ const new_annotation_node = {
215
+ id: this.doc.generate_id(),
216
+ type: annotation_type,
217
+ ...annotation_properties,
218
+ }
219
+ this.create(new_annotation_node);
248
220
  // If there's no existing annotation, add the new one
249
- annotations.push([start, end, annotation_type, annotation_data]);
221
+ annotations.push({start_offset: start, end_offset: end, node_id: new_annotation_node.id});
250
222
  }
251
223
 
252
- // Update the annotated string
253
- this.set(this.doc.selection.path, annotated_string);
254
- // Not needed anymore as doc.apply makes sure selection is rerendered
255
- // this.doc.selection = { ...this.doc.selection };
224
+ // Update the annotated text
225
+ this.set(this.doc.selection.path, annotated_text);
256
226
  return this;
257
227
  }
258
228
 
@@ -309,13 +279,15 @@ export default class Transaction {
309
279
  let text = structuredClone($state.snapshot(this.doc.get(path)));
310
280
 
311
281
  // Update the text content using character-based operations
312
- const original_text = text[0];
313
- text[0] = char_slice(original_text, 0, start) + char_slice(original_text, end, get_char_length(original_text));
282
+ const original_text = text.text;
283
+ text.text = char_slice(original_text, 0, start) + char_slice(original_text, end, get_char_length(original_text));
314
284
 
285
+ // To mark annotation nodes for deletion.
286
+ const _deleted_nodes = [];
315
287
  // Update annotation offsets for deletion
316
288
  const deletion_length = end - start;
317
- const new_annotations = text[1].map(/** @param {any} annotation */ (annotation) => {
318
- const [annotation_start, annotation_end, type, annotation_data] = annotation;
289
+ const new_annotations = text.annotations.map(/** @param {any} annotation */ (annotation) => {
290
+ const {start_offset: annotation_start, end_offset: annotation_end, node_id} = annotation;
319
291
 
320
292
  // Adjust start offset
321
293
  let new_start = annotation_start;
@@ -341,16 +313,24 @@ export default class Transaction {
341
313
 
342
314
  // Remove annotation if it becomes invalid (start >= end)
343
315
  if (new_start >= new_end) {
316
+ console.log('deleting annotation');
317
+ _deleted_nodes.push(node_id);
344
318
  return false;
345
319
  }
346
320
 
347
- return [new_start, new_end, type, annotation_data];
321
+ return {start_offset: new_start, end_offset: new_end, node_id};
348
322
  }).filter(Boolean);
349
323
 
350
- text[1] = new_annotations;
324
+ text.annotations = new_annotations;
351
325
 
352
326
  // Update the text in the entry (this implicitly records an op via this.set)
353
327
  this.set(path, text);
328
+
329
+ // Remove annotation nodes that were implicitly deleted.
330
+ for (const node_id of _deleted_nodes) {
331
+ this.delete(node_id);
332
+ }
333
+
354
334
  this.set_selection({
355
335
  type: 'text',
356
336
  path,
@@ -442,18 +422,18 @@ export default class Transaction {
442
422
  insert_text(replaced_text) {
443
423
  if (this.doc.selection.type !== 'text') return this;
444
424
 
445
- const annotated_string = structuredClone($state.snapshot(this.doc.get(this.doc.selection.path)));
425
+ const annotated_text = structuredClone($state.snapshot(this.doc.get(this.doc.selection.path)));
446
426
  const { start, end } = this.doc.get_selection_range();
447
427
 
448
428
  // Transform the plain text string using character-based operations
449
- const text = annotated_string[0];
450
- annotated_string[0] = char_slice(text, 0, start) + replaced_text + char_slice(text, end, get_char_length(text));
429
+ const text = annotated_text.text;
430
+ annotated_text.text = char_slice(text, 0, start) + replaced_text + char_slice(text, end, get_char_length(text));
451
431
 
452
- // Transform the annotations (annotated_string[1])
453
- // NOTE: Annotations are stored as [start_offset, end_offset, type]
432
+ // Transform the annotations (annotated_text.annotations)
433
+ // NOTE: Annotations are stored as {start_offset, end_offset, node_id}
454
434
  const delta = get_char_length(replaced_text) - (end - start);
455
- const new_annotations = annotated_string[1].map(/** @param {any} annotation */ (annotation) => {
456
- const [annotation_start, annotation_end, type, annotation_data] = annotation;
435
+ const new_annotations = annotated_text.annotations.map(/** @param {any} annotation */ (annotation) => {
436
+ const {start_offset: annotation_start, end_offset: annotation_end, node_id} = annotation;
457
437
 
458
438
  // Case 1: annotation is wrapped in start and end (remove it)
459
439
  if (start <= annotation_start && end >= annotation_end) {
@@ -462,7 +442,7 @@ export default class Transaction {
462
442
 
463
443
  // Case 2: text inserted before the annotation
464
444
  if (end <= annotation_start) {
465
- return [annotation_start + delta, annotation_end + delta, type, annotation_data];
445
+ return {start_offset: annotation_start + delta, end_offset: annotation_end + delta, node_id};
466
446
  }
467
447
 
468
448
  // Case 3: text inserted after the annotation
@@ -474,19 +454,19 @@ export default class Transaction {
474
454
  // NOTE: replaced_text will not be part of the annotation, we treat it the same as
475
455
  // a cursor right after the annotation
476
456
  if (start > annotation_start && start < annotation_end && end >= annotation_end) {
477
- return [annotation_start, start, type, annotation_data];
457
+ return {start_offset: annotation_start, end_offset: start, node_id};
478
458
  }
479
459
 
480
460
  // Case 5: text inserted inside an annotation
481
461
  if (start >= annotation_start && start <= annotation_end && end < annotation_end && end >= annotation_start) {
482
- return [annotation_start, annotation_end + delta, type, annotation_data];
462
+ return {start_offset: annotation_start, end_offset: annotation_end + delta, node_id};
483
463
  }
484
464
 
485
465
  // Case 6: annotation is partly selected towards left
486
466
  // NOTE: replaced_text will not be part of the annotation, we treat it the same as
487
467
  // a cursor right before the annotation
488
468
  if (start < annotation_start && end > annotation_start && end < annotation_end) {
489
- return [start + get_char_length(replaced_text), annotation_end + delta, type, annotation_data];
469
+ return {start_offset: start + get_char_length(replaced_text), end_offset: annotation_end + delta, node_id};
490
470
  }
491
471
 
492
472
  // Unhandled edge case:
@@ -496,7 +476,8 @@ export default class Transaction {
496
476
  // return annotation;
497
477
  }).filter(Boolean);
498
478
 
499
- this.set(this.doc.selection.path, [annotated_string[0], new_annotations]); // this will update the current state and create a history entry
479
+ annotated_text.annotations = new_annotations;
480
+ this.set(this.doc.selection.path, annotated_text); // this will update the current state and create a history entry
500
481
 
501
482
  // Setting the selection automatically triggers a re-render of the corresponding DOMSelection.
502
483
  const new_selection = {
@@ -578,6 +559,8 @@ export default class Transaction {
578
559
  count += value.filter(id => id === target_node_id).length;
579
560
  } else if (prop_type === 'node' && value === target_node_id) {
580
561
  count += 1;
562
+ } else if (prop_type === 'annotated_text' && value && value.annotations) {
563
+ count += value.annotations.filter(annotation => annotation.node_id === target_node_id).length;
581
564
  }
582
565
  }
583
566
  }
@@ -1 +1 @@
1
- {"version":3,"file":"commands.svelte.d.ts","sourceRoot":"","sources":["../src/lib/commands.svelte.js"],"names":[],"mappings":"AAGA,kDAqDC;AAED,iDA8DC;AAED,sDA6BC;AAED,6CA6GC"}
1
+ {"version":3,"file":"commands.svelte.d.ts","sourceRoot":"","sources":["../src/lib/commands.svelte.js"],"names":[],"mappings":"AAGA,kDAqDC;AAED,iDAsEC;AAED,sDA6BC;AAED,6CA6GC"}
@@ -1,4 +1,4 @@
1
- import { split_annotated_string, join_annotated_string, get_char_length } from './util.js';
1
+ import { split_annotated_text, join_annotated_text, get_char_length } from './util.js';
2
2
  import { get_default_node_type } from './Document.svelte.js';
3
3
 
4
4
  export function break_text_node(tr) {
@@ -30,7 +30,7 @@ export function break_text_node(tr) {
30
30
 
31
31
  const split_at_position = tr.doc.selection.anchor_offset;
32
32
  const content = tr.doc.get(selection.path);
33
- const [left_text, right_text] = split_annotated_string(content, split_at_position);
33
+ const [left_text, right_text] = split_annotated_text(content, split_at_position);
34
34
 
35
35
  tr.set([node.id, 'content'], left_text);
36
36
 
@@ -42,7 +42,7 @@ export function break_text_node(tr) {
42
42
  };
43
43
 
44
44
  // TODO: Only use default_node_type when cursor is at the end of
45
- const node_array_property_definition = doc.schema[node_array_node.type][node_array_prop];
45
+ const node_array_property_definition = doc.schema[node_array_node.type].properties[node_array_prop];
46
46
  const target_node_type = get_default_node_type(node_array_property_definition);
47
47
 
48
48
  if (!target_node_type) {
@@ -82,7 +82,7 @@ export function join_text_node(tr) {
82
82
  }
83
83
 
84
84
  // Special behavior: if we can't join and current node is empty, delete it
85
- if (!can_join && node.content[0] === '') {
85
+ if (!can_join && node.content.text === '') {
86
86
  tr.set_selection({
87
87
  type: 'node',
88
88
  path: doc.selection.path.slice(0, -2),
@@ -100,8 +100,15 @@ export function join_text_node(tr) {
100
100
 
101
101
  // Normal joining logic - both nodes are text nodes
102
102
  const previous_text_path = [...doc.selection.path.slice(0, -2), node_index - 1];
103
- const joined_text = join_annotated_string(predecessor_node.content, node.content);
103
+ const joined_text = join_annotated_text(predecessor_node.content, node.content);
104
104
 
105
+ // Calculate cursor position based on original predecessor content length
106
+ const cursor_position = get_char_length(predecessor_node.content.text);
107
+
108
+ // First set the joined content on the predecessor node (preserves annotations)
109
+ tr.set([predecessor_node.id, 'content'], joined_text);
110
+
111
+ // Then delete the current node
105
112
  tr.set_selection({
106
113
  type: 'node',
107
114
  path: doc.selection.path.slice(0, -2),
@@ -110,13 +117,14 @@ export function join_text_node(tr) {
110
117
  });
111
118
 
112
119
  tr.delete_selection();
120
+
121
+ // Finally set the cursor position at the join point using the pre-calculated position
113
122
  tr.set_selection({
114
123
  type: 'text',
115
124
  path: [...previous_text_path, 'content'],
116
- anchor_offset: get_char_length(predecessor_node.content[0]),
117
- focus_offset: get_char_length(predecessor_node.content[0]),
125
+ anchor_offset: cursor_position,
126
+ focus_offset: cursor_position,
118
127
  });
119
- tr.set([predecessor_node.id, 'content'], joined_text);
120
128
  return true;
121
129
  }
122
130
 
@@ -134,7 +142,7 @@ export function insert_default_node(tr) {
134
142
  const property_name = path.at(-1);
135
143
 
136
144
  // Get the definition for this property
137
- const property_definition = doc.schema[node_array_node.type][property_name];
145
+ const property_definition = doc.schema[node_array_node.type].properties[property_name];
138
146
  const default_type = get_default_node_type(property_definition);
139
147
 
140
148
  // Only proceed if there's exactly one allowed node_type
@@ -161,7 +169,7 @@ export function select_all(tr) {
161
169
 
162
170
  if (selection.type === 'text') {
163
171
  const text_content = doc.get(selection.path);
164
- const text_length = get_char_length(text_content[0]);
172
+ const text_length = get_char_length(text_content.text);
165
173
 
166
174
  // Check if all text is already selected
167
175
  const is_all_text_selected =
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { default as Svedit } from "./Svedit.svelte";
2
- export { default as AnnotatedStringProperty } from "./AnnotatedStringProperty.svelte";
2
+ export { default as AnnotatedTextProperty } from "./AnnotatedTextProperty.svelte";
3
3
  export { default as CustomProperty } from "./CustomProperty.svelte";
4
4
  export { default as Node } from "./Node.svelte";
5
5
  export { default as NodeArrayProperty } from "./NodeArrayProperty.svelte";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Main exports for the svedit library
2
2
  export { default as Svedit } from './Svedit.svelte';
3
- export { default as AnnotatedStringProperty } from './AnnotatedStringProperty.svelte';
3
+ export { default as AnnotatedTextProperty } from './AnnotatedTextProperty.svelte';
4
4
  export { default as CustomProperty } from './CustomProperty.svelte';
5
5
  export { default as Node } from './Node.svelte';
6
6
  export { default as NodeArrayProperty } from './NodeArrayProperty.svelte';
package/dist/types.d.ts CHANGED
@@ -68,7 +68,7 @@ export type ArrayType = "string_array" | "number_array" | "boolean_array" | "int
68
68
  /**
69
69
  * Special types for rich content.
70
70
  */
71
- export type RichType = "annotated_string";
71
+ export type RichType = "annotated_text";
72
72
 
73
73
  /**
74
74
  * Node reference types for linking to other nodes.
@@ -88,7 +88,7 @@ export type PropertyType = PrimitiveType | ReferenceType;
88
88
  /**
89
89
  * Document schema primitive types - all possible property types in document schemas.
90
90
  */
91
- export type DocumentSchemaPrimitive = "string" | "number" | "boolean" | "integer" | "datetime" | "string_array" | "number_array" | "boolean_array" | "integer_array" | "annotated_string" | "node" | "node_array";
91
+ export type DocumentSchemaPrimitive = "string" | "number" | "boolean" | "integer" | "datetime" | "string_array" | "number_array" | "boolean_array" | "integer_array" | "annotated_text" | "node" | "node_array";
92
92
 
93
93
  /**
94
94
  * Maps document schema types to their JavaScript runtime types.
@@ -103,7 +103,7 @@ export type DocumentSchemaValueToJs<T> =
103
103
  T extends "number_array" ? Array<number> :
104
104
  T extends "boolean_array" ? Array<boolean> :
105
105
  T extends "integer_array" ? Array<number> :
106
- T extends "annotated_string" ? [string, Array<any>] :
106
+ T extends "annotated_text" ? AnnotatedText :
107
107
  T extends "node" ? string :
108
108
  T extends "node_array" ? Array<string> :
109
109
  never;
@@ -112,15 +112,24 @@ export type DocumentSchemaValueToJs<T> =
112
112
  * Converts a document node schema definition to its inferred JS type.
113
113
  * Handles the {type: "..."} wrapper structure used in document schemas.
114
114
  */
115
- export type DocumentNodeToJs<S extends Record<string, {type: DocumentSchemaPrimitive}>> =
116
- { id: string, type: string } & { [K in keyof S]: DocumentSchemaValueToJs<S[K]["type"]> };
115
+ export type DocumentNodeToJs<S extends NodeSchema> =
116
+ { id: string, type: string } & { [K in keyof S["properties"]]: DocumentSchemaValueToJs<S["properties"][K]["type"]> };
117
117
 
118
118
  /**
119
- * A property that stores a primitive value.
119
+ * A property that stores an annotated text with required allow_newlines setting.
120
+ */
121
+ export type AnnotatedTextProperty = {
122
+ type: 'annotated_text';
123
+ node_types?: string[];
124
+ allow_newlines: boolean;
125
+ };
126
+
127
+ /**
128
+ * A property that stores a primitive value (excluding annotated_text).
120
129
  */
121
130
  export type PrimitiveProperty = {
122
- [K in PrimitiveType]: { type: K }
123
- }[PrimitiveType];
131
+ [K in Exclude<PrimitiveType, 'annotated_text'>]: { type: K }
132
+ }[Exclude<PrimitiveType, 'annotated_text'>];
124
133
 
125
134
  /**
126
135
  * A property that stores a reference to a single node.
@@ -143,13 +152,36 @@ export type NodeArrayProperty = {
143
152
  /**
144
153
  * Union type for all possible property definitions.
145
154
  */
146
- export type PropertyDefinition = PrimitiveProperty | NodeProperty | NodeArrayProperty;
155
+ export type PropertyDefinition = PrimitiveProperty | AnnotatedTextProperty | NodeProperty | NodeArrayProperty;
156
+
157
+ /**
158
+ * Node kind values for different types of content nodes
159
+ */
160
+ export type NodeKind = 'document' | 'block' | 'text' | 'annotation';
161
+
162
+ /**
163
+ * Schema for text nodes - must have a content property of type annotated_text
164
+ */
165
+ export type TextNodeSchema = {
166
+ kind: 'text';
167
+ properties: {
168
+ content: AnnotatedTextProperty;
169
+ } & Record<string, PropertyDefinition>;
170
+ };
171
+
172
+ /**
173
+ * Schema for non-text nodes
174
+ */
175
+ export type NonTextNodeSchema = {
176
+ kind: 'document' | 'block' | 'annotation';
177
+ properties: Record<string, PropertyDefinition>;
178
+ };
147
179
 
148
180
  /**
149
181
  * A node schema defines the structure of a specific node type.
150
- * Maps property names to their definitions.
182
+ * Contains a kind and properties object that maps property names to their definitions.
151
183
  */
152
- export type NodeSchema = Record<string, PropertyDefinition>;
184
+ export type NodeSchema = TextNodeSchema | NonTextNodeSchema;
153
185
 
154
186
  /**
155
187
  * A document schema defines all node types available in a document.
@@ -174,9 +206,9 @@ export type SerializedNode = {
174
206
  export type SerializedDocument = SerializedNode[];
175
207
 
176
208
  /**
177
- * Props for the AnnotatedStringProperty component
209
+ * Props for the AnnotatedTextProperty component
178
210
  */
179
- export type AnnotatedStringPropertyProps = {
211
+ export type AnnotatedTextPropertyProps = {
180
212
  /** The full path to the property */
181
213
  path: DocumentPath;
182
214
  /** The `class` attribute on the content element */
@@ -239,26 +271,39 @@ export type SveditProps = {
239
271
  editable?: boolean,
240
272
  /** The path to the root element (e.g. ['page_1']) */
241
273
  path: DocumentPath,
242
- /** The `class` attribute on the content element */
274
+ /** The `class` attribute on the canvas element */
243
275
  class?: string;
276
+ /** The `autocapitalize` attribute on the canvas element */
277
+ autocapitalize?: 'on' | 'off';
278
+ /** The `spellcheck` attribute on the canvas element */
279
+ spellcheck?: 'true' | 'false';
244
280
  };
245
281
 
246
282
  /**
247
283
  * Represents an annotation in an annotated string
248
- * Format: [start_offset, end_offset, type, options?]
249
284
  */
250
- export type Annotation = [number, number, string, Record<string, any>?];
285
+ export type Annotation = {
286
+ start_offset: number;
287
+ end_offset: number;
288
+ node_id: NodeId;
289
+ };
290
+
291
+ /**
292
+ * Represents an annotated text with text and annotations
293
+ */
294
+ export type AnnotatedText = {
295
+ text: string;
296
+ annotations: Array<Annotation>;
297
+ };
251
298
 
252
299
  /**
253
300
  * Represents a fragment of annotated text content
254
301
  */
255
- export type AnnotationFragment = {
256
- /** The annotation type (e.g., 'link', 'emphasis', 'strong') */
257
- type: string;
302
+ export type AnnotationFragment = string | {
303
+ /** NodeId that has annotation type and details */
304
+ node: any;
258
305
  /** The text content of the annotation */
259
306
  content: string;
260
307
  /** Index of the annotation in the original array */
261
308
  annotation_index: number;
262
- /** Optional properties from the annotation's options object */
263
- data?: any;
264
309
  };
package/dist/util.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { Annotation } from './types.d.ts';
2
+ * @import { Annotation, AnnotatedText } from './types.d.ts';
3
3
  */
4
4
  /**
5
5
  * Get the actual character length (accounting for multi-byte characters)
@@ -79,39 +79,39 @@ export function utf16_to_char_offset(str: string, utf16_offset: number): number;
79
79
  */
80
80
  export function char_to_utf16_offset(str: string, char_offset: number): number;
81
81
  /**
82
- * Splits an annotated string at the specified character position.
82
+ * Splits an annotated text at the specified character position.
83
83
  *
84
84
  * Annotations that span the split point will be divided appropriately,
85
85
  * with offsets adjusted for each resulting part.
86
86
  *
87
- * @param {[string, Array<Annotation>]} text_with_annotations - Tuple of [text, annotations] where annotations follow the Annotation type: [start, end, type, data?]
87
+ * @param {AnnotatedText} text_with_annotations - Annotated text object
88
88
  * @param {number} at_position - Character position where to split (0-based)
89
- * @returns {[[string, Array<Annotation>], [string, Array<Annotation>]]} Tuple of [left_part, right_part] where each part is [text, annotations]
89
+ * @returns {[AnnotatedText, AnnotatedText]} Tuple of [left_part, right_part]
90
90
  *
91
91
  * @example
92
- * split_annotated_string(["Hello world", [[6,11, "strong"]]], 8)
92
+ * split_annotated_text({text: "Hello world", annotations: [{start_offset: 6, end_offset: 11, node_id: "strong"}]}, 8)
93
93
  * // Returns:
94
94
  * // [
95
- * // ["Hello wo", [[6,8, "strong"]]]
96
- * // ["rld", [[0,3, "strong"]]]
95
+ * // {text: "Hello wo", annotations: [{start_offset: 6, end_offset: 8, node_id: "strong"}]},
96
+ * // {text: "rld", annotations: [{start_offset: 0, end_offset: 3, node_id: "strong"}]}
97
97
  * // ]
98
98
  */
99
- export function split_annotated_string(text_with_annotations: [string, Array<Annotation>], at_position: number): [[string, Array<Annotation>], [string, Array<Annotation>]];
99
+ export function split_annotated_text(text_with_annotations: AnnotatedText, at_position: number): [AnnotatedText, AnnotatedText];
100
100
  /**
101
- * Joins two annotated strings into a single annotated string.
101
+ * Joins two annotated texts into a single annotated text.
102
102
  *
103
103
  * Annotations from the second text will have their offsets shifted by the length
104
104
  * of the first text. Adjacent annotations of the same type and data will be merged.
105
105
  *
106
- * @param {[string, Array<Annotation>]} first_text - First annotated string tuple where annotations follow the Annotation type: [start, end, type, data?]
107
- * @param {[string, Array<Annotation>]} second_text - Second annotated string tuple where annotations follow the Annotation type: [start, end, type, data?]
108
- * @returns {[string, Array<Annotation>]} Combined annotated string tuple [text, annotations]
106
+ * @param {AnnotatedText} first_text - First annotated text object
107
+ * @param {AnnotatedText} second_text - Second annotated text object
108
+ * @returns {AnnotatedText} Combined annotated text object
109
109
  *
110
110
  * @example
111
- * join_annotated_string(["Hello wo", [[6,8, "strong"]]], ["rld", [[0,3, "strong"]]])
112
- * // Returns: ["Hello world", [[6,11, "strong"]]]
111
+ * join_annotated_text({text: "Hello wo", annotations: [{start_offset: 6, end_offset: 8, node_id: "strong"}]}, {text: "rld", annotations: [{start_offset: 0, end_offset: 3, node_id: "strong"}]})
112
+ * // Returns: {text: "Hello world", annotations: [{start_offset: 6, end_offset: 11, node_id: "strong"}]}
113
113
  */
114
- export function join_annotated_string(first_text: [string, Array<Annotation>], second_text: [string, Array<Annotation>]): [string, Array<Annotation>];
114
+ export function join_annotated_text(first_text: AnnotatedText, second_text: AnnotatedText): AnnotatedText;
115
115
  /**
116
116
  * Convert snake_case string to PascalCase
117
117
  *
@@ -122,5 +122,5 @@ export function join_annotated_string(first_text: [string, Array<Annotation>], s
122
122
  * snake_to_pascal('list_item') // Returns: 'ListItem'
123
123
  */
124
124
  export function snake_to_pascal(str: string): string;
125
- import type { Annotation } from './types.d.ts';
125
+ import type { AnnotatedText } from './types.d.ts';
126
126
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/lib/util.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;GAaG;AACH,qCARW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;;GAcG;AACH,iCATW,MAAM,SACN,MAAM,GACJ,MAAM,CAWlB;AAED;;;;;;;;;;;;;;GAcG;AACH,gCATW,MAAM,SACN,MAAM,QACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;GAaG;AACH,0CARW,MAAM,gBACN,MAAM,GACJ,MAAM,CAoBlB;AAED;;;;;;;;;;;;;GAaG;AACH,0CARW,MAAM,eACN,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,8DAZW,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,eAC3B,MAAM,GACJ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAyCtE;AAGD;;;;;;;;;;;;;GAaG;AACH,kDARW,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,eAC3B,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,GACzB,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAsCvC;AAED;;;;;;;;GAQG;AACH,qCANW,MAAM,GACJ,MAAM,CAUlB;gCA1O8B,cAAc"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/lib/util.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;GAaG;AACH,qCARW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;;GAcG;AACH,iCATW,MAAM,SACN,MAAM,GACJ,MAAM,CAWlB;AAED;;;;;;;;;;;;;;GAcG;AACH,gCATW,MAAM,SACN,MAAM,QACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;GAaG;AACH,0CARW,MAAM,gBACN,MAAM,GACJ,MAAM,CAoBlB;AAED;;;;;;;;;;;;;GAaG;AACH,0CARW,MAAM,eACN,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,4DAZW,aAAa,eACb,MAAM,GACJ,CAAC,aAAa,EAAE,aAAa,CAAC,CAyC1C;AAGD;;;;;;;;;;;;;GAaG;AACH,gDARW,aAAa,eACb,aAAa,GACX,aAAa,CAqCzB;AAED;;;;;;;;GAQG;AACH,qCANW,MAAM,GACJ,MAAM,CAUlB;mCAzO6C,cAAc"}