@itwin/core-common 5.2.0-dev.8 → 5.3.0-dev.2

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 (82) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/lib/cjs/BriefcaseTypes.d.ts +2 -0
  3. package/lib/cjs/BriefcaseTypes.d.ts.map +1 -1
  4. package/lib/cjs/BriefcaseTypes.js.map +1 -1
  5. package/lib/cjs/ElementProps.d.ts +8 -0
  6. package/lib/cjs/ElementProps.d.ts.map +1 -1
  7. package/lib/cjs/ElementProps.js.map +1 -1
  8. package/lib/cjs/FeatureSymbology.d.ts.map +1 -1
  9. package/lib/cjs/FeatureSymbology.js +0 -2
  10. package/lib/cjs/FeatureSymbology.js.map +1 -1
  11. package/lib/cjs/annotation/TextAnnotation.d.ts +1 -1
  12. package/lib/cjs/annotation/TextAnnotation.d.ts.map +1 -1
  13. package/lib/cjs/annotation/TextAnnotation.js +1 -1
  14. package/lib/cjs/annotation/TextAnnotation.js.map +1 -1
  15. package/lib/cjs/annotation/TextBlock.d.ts +114 -104
  16. package/lib/cjs/annotation/TextBlock.d.ts.map +1 -1
  17. package/lib/cjs/annotation/TextBlock.js +227 -108
  18. package/lib/cjs/annotation/TextBlock.js.map +1 -1
  19. package/lib/cjs/annotation/TextBlockLayoutResult.d.ts +3 -5
  20. package/lib/cjs/annotation/TextBlockLayoutResult.d.ts.map +1 -1
  21. package/lib/cjs/annotation/TextBlockLayoutResult.js.map +1 -1
  22. package/lib/cjs/annotation/TextField.d.ts +86 -0
  23. package/lib/cjs/annotation/TextField.d.ts.map +1 -0
  24. package/lib/cjs/annotation/TextField.js +10 -0
  25. package/lib/cjs/annotation/TextField.js.map +1 -0
  26. package/lib/cjs/annotation/TextStyle.d.ts +63 -1
  27. package/lib/cjs/annotation/TextStyle.d.ts.map +1 -1
  28. package/lib/cjs/annotation/TextStyle.js +44 -4
  29. package/lib/cjs/annotation/TextStyle.js.map +1 -1
  30. package/lib/cjs/core-common.d.ts +1 -0
  31. package/lib/cjs/core-common.d.ts.map +1 -1
  32. package/lib/cjs/core-common.js +1 -0
  33. package/lib/cjs/core-common.js.map +1 -1
  34. package/lib/cjs/internal/annotations/FieldFormatter.d.ts +18 -0
  35. package/lib/cjs/internal/annotations/FieldFormatter.d.ts.map +1 -0
  36. package/lib/cjs/internal/annotations/FieldFormatter.js +66 -0
  37. package/lib/cjs/internal/annotations/FieldFormatter.js.map +1 -0
  38. package/lib/cjs/internal/cross-package.d.ts +1 -0
  39. package/lib/cjs/internal/cross-package.d.ts.map +1 -1
  40. package/lib/cjs/internal/cross-package.js +4 -1
  41. package/lib/cjs/internal/cross-package.js.map +1 -1
  42. package/lib/esm/BriefcaseTypes.d.ts +2 -0
  43. package/lib/esm/BriefcaseTypes.d.ts.map +1 -1
  44. package/lib/esm/BriefcaseTypes.js.map +1 -1
  45. package/lib/esm/ElementProps.d.ts +8 -0
  46. package/lib/esm/ElementProps.d.ts.map +1 -1
  47. package/lib/esm/ElementProps.js.map +1 -1
  48. package/lib/esm/FeatureSymbology.d.ts.map +1 -1
  49. package/lib/esm/FeatureSymbology.js +0 -2
  50. package/lib/esm/FeatureSymbology.js.map +1 -1
  51. package/lib/esm/annotation/TextAnnotation.d.ts +1 -1
  52. package/lib/esm/annotation/TextAnnotation.d.ts.map +1 -1
  53. package/lib/esm/annotation/TextAnnotation.js +1 -1
  54. package/lib/esm/annotation/TextAnnotation.js.map +1 -1
  55. package/lib/esm/annotation/TextBlock.d.ts +114 -104
  56. package/lib/esm/annotation/TextBlock.d.ts.map +1 -1
  57. package/lib/esm/annotation/TextBlock.js +223 -107
  58. package/lib/esm/annotation/TextBlock.js.map +1 -1
  59. package/lib/esm/annotation/TextBlockLayoutResult.d.ts +3 -5
  60. package/lib/esm/annotation/TextBlockLayoutResult.d.ts.map +1 -1
  61. package/lib/esm/annotation/TextBlockLayoutResult.js.map +1 -1
  62. package/lib/esm/annotation/TextField.d.ts +86 -0
  63. package/lib/esm/annotation/TextField.d.ts.map +1 -0
  64. package/lib/esm/annotation/TextField.js +9 -0
  65. package/lib/esm/annotation/TextField.js.map +1 -0
  66. package/lib/esm/annotation/TextStyle.d.ts +63 -1
  67. package/lib/esm/annotation/TextStyle.d.ts.map +1 -1
  68. package/lib/esm/annotation/TextStyle.js +43 -3
  69. package/lib/esm/annotation/TextStyle.js.map +1 -1
  70. package/lib/esm/core-common.d.ts +1 -0
  71. package/lib/esm/core-common.d.ts.map +1 -1
  72. package/lib/esm/core-common.js +1 -0
  73. package/lib/esm/core-common.js.map +1 -1
  74. package/lib/esm/internal/annotations/FieldFormatter.d.ts +18 -0
  75. package/lib/esm/internal/annotations/FieldFormatter.d.ts.map +1 -0
  76. package/lib/esm/internal/annotations/FieldFormatter.js +62 -0
  77. package/lib/esm/internal/annotations/FieldFormatter.js.map +1 -0
  78. package/lib/esm/internal/cross-package.d.ts +1 -0
  79. package/lib/esm/internal/cross-package.d.ts.map +1 -1
  80. package/lib/esm/internal/cross-package.js +1 -0
  81. package/lib/esm/internal/cross-package.js.map +1 -1
  82. package/package.json +6 -6
@@ -5,9 +5,19 @@
5
5
  /** @packageDocumentation
6
6
  * @module Annotation
7
7
  */
8
- import { TextStyleSettings } from "./TextStyle";
9
- /** Abstract representation of any of the building blocks that make up a [[TextBlock]] document - namely [[Run]]s, [[Paragraph]]s, and [[TextBlock]] itself.
10
- * The [[TextBlock]] can specify an [AnnotationTextStyle]($backend) that formats its contents. Each component can specify an optional [[styleOverrides]] to customize that formatting.
8
+ import { ListMarkerEnumerator, TextStyleSettings } from "./TextStyle";
9
+ function clearStyleOverrides(component, options) {
10
+ component.styleOverrides = {};
11
+ if (!options?.preserveChildrenOverrides) {
12
+ for (const child of component.children) {
13
+ child.clearStyleOverrides(options);
14
+ }
15
+ }
16
+ }
17
+ /**
18
+ * Abstract representation of any of the building blocks that make up a [[TextBlock]] document - namely [[Run]]s and [[StructuralTextBlockComponent]]s.
19
+ * The [[TextBlock]] can specify an [AnnotationTextStyle]($backend) that formats its contents.
20
+ * Each component can specify an optional [[styleOverrides]] to customize that formatting.
11
21
  * @beta
12
22
  */
13
23
  export class TextBlockComponent {
@@ -16,7 +26,7 @@ export class TextBlockComponent {
16
26
  constructor(props) {
17
27
  this._styleOverrides = TextStyleSettings.cloneProps(props?.styleOverrides ?? {});
18
28
  }
19
- /** Deviations in individual properties of the [[TextStyleSettings]] in the [AnnotationTextStyle]($backend) specified by `styleId` on the [[TextBlock]].
29
+ /** Deviations in individual properties of the [[TextStyleSettings]] in the [AnnotationTextStyle]($backend).
20
30
  * For example, if the style uses the "Arial" font, you can override that by settings `styleOverrides.fontName` to "Comic Sans".
21
31
  * @see [[clearStyleOverrides]] to reset this to an empty object.
22
32
  */
@@ -72,15 +82,15 @@ export class TextBlockComponent {
72
82
  export var Run;
73
83
  (function (Run) {
74
84
  /** Create a run from its JSON representation.
75
- * @see [[TextRun.create]], [[FractionRun.create]], and [[LineBreakRun.create]] to create a run directly.
85
+ * @see [[TextRun.create]], [[FractionRun.create]], [[FieldRun.create]], [[TabRun.create]], and [[LineBreakRun.create]] to create a run directly.
76
86
  */
77
87
  function fromJSON(props) {
78
88
  switch (props.type) {
79
- case "text": return TextRun.create(props);
89
+ case "field": return FieldRun.create(props);
80
90
  case "fraction": return FractionRun.create(props);
81
- case "tab": return TabRun.create(props);
82
91
  case "linebreak": return LineBreakRun.create(props);
83
- case "field": return FieldRun.create(props);
92
+ case "tab": return TabRun.create(props);
93
+ case "text": return TextRun.create(props);
84
94
  }
85
95
  }
86
96
  Run.fromJSON = fromJSON;
@@ -112,7 +122,10 @@ export class TextRun extends TextBlockComponent {
112
122
  };
113
123
  }
114
124
  static create(props) {
115
- return new TextRun(props);
125
+ return new TextRun({ ...props, type: "text" });
126
+ }
127
+ get isEmpty() {
128
+ return this.stringify().length === 0;
116
129
  }
117
130
  /** Simply returns [[content]]. */
118
131
  stringify() {
@@ -150,7 +163,10 @@ export class FractionRun extends TextBlockComponent {
150
163
  return new FractionRun(this.toJSON());
151
164
  }
152
165
  static create(props) {
153
- return new FractionRun(props);
166
+ return new FractionRun({ ...props, type: "fraction" });
167
+ }
168
+ get isEmpty() {
169
+ return this.stringify().length === 0;
154
170
  }
155
171
  /** Formats the fraction as a string with the [[numerator]] and [[denominator]] separated by [[TextBlockStringifyOptions.fractionSeparator]]. */
156
172
  stringify(options) {
@@ -177,11 +193,14 @@ export class LineBreakRun extends TextBlockComponent {
177
193
  };
178
194
  }
179
195
  static create(props) {
180
- return new LineBreakRun(props);
196
+ return new LineBreakRun({ ...props, type: "linebreak" });
181
197
  }
182
198
  clone() {
183
199
  return new LineBreakRun(this.toJSON());
184
200
  }
201
+ get isEmpty() {
202
+ return this.stringify().length === 0;
203
+ }
185
204
  /** Simply returns [[TextBlockStringifyOptions.lineBreak]]. */
186
205
  stringify(options) {
187
206
  return options?.lineBreak ?? " ";
@@ -209,6 +228,9 @@ export class TabRun extends TextBlockComponent {
209
228
  static create(props) {
210
229
  return new TabRun(props);
211
230
  }
231
+ get isEmpty() {
232
+ return this.stringify().length === 0;
233
+ }
212
234
  /**
213
235
  * Converts a [[TabRun]] to its string representation.
214
236
  * If the `tabsAsSpaces` option is provided, returns a string of spaces of the specified length.
@@ -227,7 +249,8 @@ export class TabRun extends TextBlockComponent {
227
249
  /** A [[Run]] that displays the formatted value of a property of some [Element]($backend).
228
250
  * When a [[TextBlock]] containing a [[FieldRun]] is written into the iModel as an [ITextAnnotation]($backend) element,
229
251
  * a dependency is established between the two elements via the [ElementDrivesTextAnnotation]($backend) relationship such that
230
- * whenever the source element specified by [[propertyHost]] is modified, the field(s) in the `ITextAnnotation` element are automatically
252
+ * whenever the source element specified by [[propertyHost]] is modified or the `ITextAnnotation` element is inserted or updated in the iModel,
253
+ * the field(s) in the `ITextAnnotation` element are automatically
231
254
  * recalculated, causing their [[cachedContent]] to update. If the field's display string cannot be evaluated (for example, because the specified element or
232
255
  * property does not exist), then its cached content is set to [[FieldRun.invalidContentIndicator]].
233
256
  * A [[FieldRun]] displays its [[cachedContent]] in the same way that [[TextRun]]s display their `content`, including word wrapping where appropriate.
@@ -242,8 +265,10 @@ export class FieldRun extends TextBlockComponent {
242
265
  propertyHost;
243
266
  /** Describes how to obtain the property value from [[propertyHost]]. */
244
267
  propertyPath;
245
- /** Specifies how to format the property value obtained from [[propertyPath]] into a string to be stored in [[cachedContent]]. */
246
- formatter;
268
+ /** Specifies how to format the property value obtained from [[propertyPath]] into a string to be stored in [[cachedContent]].
269
+ * The specific options used depend upon the [[FieldPropertyType]].
270
+ */
271
+ formatOptions;
247
272
  _cachedContent;
248
273
  /** The field's most recently evaluated display string. */
249
274
  get cachedContent() {
@@ -258,7 +283,7 @@ export class FieldRun extends TextBlockComponent {
258
283
  this._cachedContent = props.cachedContent ?? FieldRun.invalidContentIndicator;
259
284
  this.propertyHost = props.propertyHost;
260
285
  this.propertyPath = props.propertyPath;
261
- this.formatter = props.formatter;
286
+ this.formatOptions = props.formatOptions;
262
287
  }
263
288
  /** Create a FieldRun from its JSON representation. */
264
289
  static create(props) {
@@ -266,7 +291,8 @@ export class FieldRun extends TextBlockComponent {
266
291
  ...props,
267
292
  propertyHost: { ...props.propertyHost },
268
293
  propertyPath: structuredClone(props.propertyPath),
269
- formatter: structuredClone(props.formatter),
294
+ formatOptions: structuredClone(props.formatOptions),
295
+ type: "field",
270
296
  });
271
297
  }
272
298
  /** Convert the FieldRun to its JSON representation. */
@@ -280,8 +306,8 @@ export class FieldRun extends TextBlockComponent {
280
306
  if (this.cachedContent !== FieldRun.invalidContentIndicator) {
281
307
  json.cachedContent = this.cachedContent;
282
308
  }
283
- if (this.formatter) {
284
- json.formatter = structuredClone(this.formatter);
309
+ if (this.formatOptions) {
310
+ json.formatOptions = structuredClone(this.formatOptions);
285
311
  }
286
312
  return json;
287
313
  }
@@ -289,6 +315,9 @@ export class FieldRun extends TextBlockComponent {
289
315
  clone() {
290
316
  return new FieldRun(this.toJSON());
291
317
  }
318
+ get isEmpty() {
319
+ return this.stringify().length === 0;
320
+ }
292
321
  /** Convert this FieldRun to a simple string representation. */
293
322
  stringify() {
294
323
  return this.cachedContent;
@@ -308,91 +337,116 @@ export class FieldRun extends TextBlockComponent {
308
337
  }
309
338
  const thisAccessors = this.propertyPath.accessors ?? [];
310
339
  const otherAccessors = other.propertyPath.accessors ?? [];
311
- const thisJsonAccessors = this.propertyPath.jsonAccessors ?? [];
312
- const otherJsonAccessors = other.propertyPath.jsonAccessors ?? [];
313
- if (thisAccessors.length !== otherAccessors.length || thisJsonAccessors.length !== otherJsonAccessors.length) {
340
+ if (thisAccessors.length !== otherAccessors.length) {
314
341
  return false;
315
342
  }
316
343
  if (!thisAccessors.every((value, index) => value === otherAccessors[index])) {
317
344
  return false;
318
345
  }
319
- if (!thisJsonAccessors.every((value, index) => value === otherJsonAccessors[index])) {
320
- return false;
321
- }
322
- if (this.formatter && other.formatter) {
323
- // ###TODO better comparison of formatter objects.
324
- if (JSON.stringify(this.formatter) !== JSON.stringify(other.formatter)) {
346
+ if (this.formatOptions && other.formatOptions) {
347
+ // We anticipate new formatting options being added in the future.
348
+ // So to account for properties we don't know about, just compare the string representations.
349
+ if (JSON.stringify(this.formatOptions) !== JSON.stringify(other.formatOptions)) {
325
350
  return false;
326
351
  }
327
352
  }
328
- else if (this.formatter || other.formatter) {
353
+ else if (this.formatOptions || other.formatOptions) {
329
354
  return false;
330
355
  }
331
356
  return true;
332
357
  }
333
358
  }
334
- /** A collection of [[Run]]s within a [[TextBlock]]. Each paragraph within a text block is laid out on a separate line.
359
+ /** A collection of [[Run]]s and [[List]]s. Paragraphs can be appended to [[List]]s and [[TextBlock]]s.
360
+ * Each paragraph is laid out on a separate line. If included in a [[List]], the paragraph will be treated as a list item.
335
361
  * @beta
336
362
  */
337
363
  export class Paragraph extends TextBlockComponent {
338
- /** The runs within the paragraph. You can modify the contents of this array to change the content of the paragraph. */
339
- runs;
364
+ type = "paragraph";
365
+ children;
340
366
  constructor(props) {
341
367
  super(props);
342
- this.runs = props?.runs?.map((run) => Run.fromJSON(run)) ?? [];
368
+ this.children = props?.children?.map((child) => child.type === "list" ? List.create(child) : Run.fromJSON(child)) ?? [];
369
+ }
370
+ /** Create a paragraph from its JSON representation. */
371
+ static create(props) {
372
+ return new Paragraph(props);
373
+ }
374
+ clearStyleOverrides(options) {
375
+ clearStyleOverrides(this, options);
376
+ }
377
+ get isEmpty() {
378
+ return this.children.length === 0;
379
+ }
380
+ clone() {
381
+ return new Paragraph(this.toJSON());
343
382
  }
344
383
  toJSON() {
345
384
  return {
346
385
  ...super.toJSON(),
347
- runs: this.runs.map((run) => run.toJSON()),
386
+ children: this.children.map((child) => child.toJSON()),
348
387
  };
349
388
  }
350
- /** Create a paragraph from its JSON representation. */
389
+ /** Compute a string representation of this paragraph by concatenating the string representations of all of its children. */
390
+ stringify(options, context) {
391
+ return this.children.map((x, index) => (index > 0 && x.type === "list") ? `${options?.paragraphBreak ?? " "}${x.stringify(options, context)}` : x.stringify(options, context)).join("") ?? "";
392
+ }
393
+ equals(other) {
394
+ return (other instanceof Paragraph) && super.equals(other);
395
+ }
396
+ }
397
+ /** A collection of list items ([[Paragraph]]s). Lists can be appended to [[Paragraph]]s.
398
+ * Lists will be laid out on a new line. Each item in a list is laid out on a separate line.
399
+ * @beta
400
+ */
401
+ export class List extends TextBlockComponent {
402
+ type = "list";
403
+ children;
404
+ constructor(props) {
405
+ super(props);
406
+ this.children = props?.children?.map((child) => Paragraph.create(child)) ?? [];
407
+ }
408
+ /** Create a list from its JSON representation. */
351
409
  static create(props) {
352
- return new Paragraph(props);
410
+ return new List({ ...props, type: "list" });
411
+ }
412
+ clearStyleOverrides(options) {
413
+ clearStyleOverrides(this, options);
414
+ }
415
+ get isEmpty() {
416
+ return this.children.length === 0;
353
417
  }
354
418
  clone() {
355
- return new Paragraph(this.toJSON());
419
+ return new List(this.toJSON());
356
420
  }
357
- /**
358
- * Clears any [[styleOverrides]] applied to this Paragraph.
359
- * Will also clear [[styleOverrides]] from all child components unless [[ClearTextStyleOptions.preserveChildrenOverrides]] is `true`.
360
- */
361
- clearStyleOverrides(options) {
362
- super.clearStyleOverrides();
363
- if (options?.preserveChildrenOverrides)
364
- return;
365
- for (const run of this.runs) {
366
- run.clearStyleOverrides();
367
- }
421
+ toJSON() {
422
+ return {
423
+ ...super.toJSON(),
424
+ type: "list",
425
+ children: this.children.map((run) => run.toJSON()),
426
+ };
368
427
  }
369
- /** Compute a string representation of this paragraph by concatenating the string representations of all of its [[runs]]. */
370
- stringify(options) {
371
- return this.runs.map((x) => x.stringify(options)).join("");
428
+ /** Compute a string representation of this list by concatenating the string representations of all of its [[children]]. */
429
+ stringify(options, context) {
430
+ const children = this.children.map((x, index) => {
431
+ const depth = context?.depth ?? 0;
432
+ const marker = getMarkerText(this.styleOverrides.listMarker ?? TextStyleSettings.defaultProps.listMarker, index + 1);
433
+ const tab = (options?.tabsAsSpaces ? " ".repeat(options.tabsAsSpaces) : "\t").repeat(depth);
434
+ return `${tab}${marker}${options?.listMarkerBreak ?? " "}${x.stringify(options, { depth: depth + 1 })}`;
435
+ });
436
+ return children.join(options?.paragraphBreak ?? " ") ?? "";
372
437
  }
373
438
  equals(other) {
374
- if (!(other instanceof Paragraph)) {
375
- return false;
376
- }
377
- if (this.runs.length !== other.runs.length || !super.equals(other)) {
378
- return false;
379
- }
380
- return this.runs.every((run, index) => run.equals(other.runs[index]));
439
+ return (other instanceof List) && super.equals(other);
381
440
  }
382
441
  }
383
442
  ;
384
- /** Represents a formatted text document consisting of a series of [[Paragraph]]s, each laid out on a separate line and containing their own content in the form of [[Run]]s.
385
- * You can change the content of the document by directly modifying the contents of its [[paragraphs]], or via [[appendParagraph]] and [[appendRun]].
443
+ /** Represents a formatted text document consisting of a series of [[Paragraph]]s, each laid out on a separate line and containing their own content.
386
444
  * No word-wrapping is applied to the document unless a [[width]] greater than zero is specified.
387
445
  * @see [[TextAnnotation]] to position a text block as an annotation in 2d or 3d space.
388
446
  * @beta
389
447
  */
390
448
  export class TextBlock extends TextBlockComponent {
391
- /** The ID of the [AnnotationTextStyle]($backend) that provides the base formatting for the contents of this TextBlock.
392
- * @note Assigning to this property retains all style overrides on the TextBlock and its child components.
393
- * Call [[clearStyleOverrides]] to clear the TextBlock's and optionally all children's style overrides.
394
- */
395
- styleId;
449
+ children;
396
450
  /** The width of the document in meters. Lines that would exceed this width are instead wrapped around to the next line if possible.
397
451
  * A value less than or equal to zero indicates no wrapping is to be applied.
398
452
  * Default: 0
@@ -402,11 +456,8 @@ export class TextBlock extends TextBlockComponent {
402
456
  justification;
403
457
  /** The margins of the document. */
404
458
  margins;
405
- /** The ordered list of paragraphs within the document. */
406
- paragraphs;
407
459
  constructor(props) {
408
460
  super(props);
409
- this.styleId = props.styleId;
410
461
  this.width = props.width ?? 0;
411
462
  this.justification = props.justification ?? "left";
412
463
  // Assign default margins if not provided
@@ -416,86 +467,151 @@ export class TextBlock extends TextBlockComponent {
416
467
  top: props.margins?.top ?? 0,
417
468
  bottom: props.margins?.bottom ?? 0,
418
469
  };
419
- this.paragraphs = props.paragraphs?.map((x) => Paragraph.create(x)) ?? [];
470
+ this.children = props?.children?.map((para) => Paragraph.create(para)) ?? [];
471
+ }
472
+ clearStyleOverrides(options) {
473
+ clearStyleOverrides(this, options);
420
474
  }
421
475
  toJSON() {
422
476
  return {
423
477
  ...super.toJSON(),
424
- styleId: this.styleId,
425
478
  width: this.width,
426
479
  justification: this.justification,
427
480
  margins: this.margins,
428
- paragraphs: this.paragraphs.map((x) => x.toJSON()),
481
+ children: this.children.map((x) => x.toJSON()),
429
482
  };
430
483
  }
431
484
  /** Create a text block from its JSON representation. */
432
485
  static create(props) {
433
- return new TextBlock(props);
434
- }
435
- /** Create an empty text block containing no [[paragraphs]] and an empty [[styleId]]. */
436
- static createEmpty() {
437
- return TextBlock.create({ styleId: "" });
486
+ return new TextBlock(props ?? {});
438
487
  }
439
488
  /** Returns true if every paragraph in this text block is empty. */
440
489
  get isEmpty() {
441
- return this.paragraphs.every((p) => p.runs.length === 0);
490
+ return !this.children || this.children.every((child) => child.isEmpty);
442
491
  }
443
492
  clone() {
444
493
  return new TextBlock(this.toJSON());
445
494
  }
446
- /**
447
- * Clears any [[styleOverrides]] applied to this TextBlock.
448
- * Will also clear [[styleOverrides]] from all child components unless [[ClearTextStyleOptions.preserveChildrenOverrides]] is `true`.
449
- */
450
- clearStyleOverrides(options) {
451
- super.clearStyleOverrides();
452
- if (options?.preserveChildrenOverrides)
453
- return;
454
- for (const paragraph of this.paragraphs) {
455
- paragraph.clearStyleOverrides();
456
- }
457
- }
458
- /** Compute a string representation of the document's contents by concatenating the string representations of each of its [[paragraphs]], separated by [[TextBlockStringifyOptions.paragraphBreak]]. */
495
+ /** Compute a string representation of the document's contents by concatenating the string representations of each of its [[children]], separated by [[TextBlockStringifyOptions.paragraphBreak]]. */
459
496
  stringify(options) {
460
- return this.paragraphs.map((x) => x.stringify(options)).join(options?.paragraphBreak ?? " ");
497
+ return this.children.map((x) => x.stringify(options)).join(options?.paragraphBreak ?? " ") || "";
461
498
  }
462
499
  /** Add and return a new paragraph.
463
500
  * By default, the paragraph will be created with no [[styleOverrides]], so that it inherits the style of this block.
464
- * @param seedFromLast If true and [[paragraphs]] is not empty, the new paragraph will inherit the style overrides of the last [[Paragraph]] in this block.
501
+ * @param seedFromLast If true and [[children]] is not empty, the new paragraph will inherit the style overrides of the last child in this block.
502
+ * @note Be sure you pass in [[ParagraphProps]] and not [[Paragraph]] or style overrides will be ignored.
465
503
  */
466
- appendParagraph(seedFromLast = false) {
467
- let styleOverrides = {};
468
- if (seedFromLast && this.paragraphs.length > 0) {
469
- const seed = this.paragraphs[this.paragraphs.length - 1];
470
- styleOverrides = { ...seed.styleOverrides };
471
- }
472
- const paragraph = Paragraph.create({
473
- styleOverrides
474
- });
475
- this.paragraphs.push(paragraph);
504
+ appendParagraph(props, seedFromLast = false) {
505
+ const seed = seedFromLast ? this.children[this.children.length - 1] : undefined;
506
+ const styleOverrides = { ...seed?.styleOverrides, ...props?.styleOverrides };
507
+ const paragraph = Paragraph.create({ ...props, styleOverrides });
508
+ this.children.push(paragraph);
476
509
  return paragraph;
477
510
  }
478
511
  /** Append a run to the last [[Paragraph]] in this block.
479
- * If the block contains no [[paragraphs]], a new one will first be created using [[appendParagraph]].
512
+ * If the block contains no [[children]], a new [[Paragraph]] will first be created using [[appendParagraph]].
480
513
  */
481
514
  appendRun(run) {
482
- const paragraph = this.paragraphs[this.paragraphs.length - 1] ?? this.appendParagraph();
483
- paragraph.runs.push(run);
515
+ const paragraph = this.children[this.children.length - 1] ?? this.appendParagraph();
516
+ paragraph.children.push(run);
484
517
  }
485
518
  equals(other) {
486
519
  if (!(other instanceof TextBlock)) {
487
520
  return false;
488
521
  }
489
- if (this.styleId !== other.styleId || !super.equals(other)) {
522
+ if (!super.equals(other)) {
490
523
  return false;
491
524
  }
492
- if (this.width !== other.width || this.justification !== other.justification || this.paragraphs.length !== other.paragraphs.length) {
525
+ if (this.width !== other.width || this.justification !== other.justification) {
493
526
  return false;
494
527
  }
495
528
  const marginsAreEqual = Object.entries(this.margins).every(([key, value]) => value === other.margins[key]);
496
529
  if (!marginsAreEqual)
497
530
  return false;
498
- return this.paragraphs.every((paragraph, index) => paragraph.equals(other.paragraphs[index]));
531
+ if (this.children && other.children) {
532
+ if (this.children.length !== other.children.length) {
533
+ return false;
534
+ }
535
+ return this.children.every((child, index) => other.children && child.equals(other.children[index]));
536
+ }
537
+ return true;
499
538
  }
500
539
  }
540
+ /**
541
+ * Recursively traverses a [[StructuralTextBlockComponent]] tree, yielding each child component along with its parent container.
542
+ * This generator enables depth-first iteration over all components in a text block structure, including paragraphs, lists, and runs.
543
+ *
544
+ * @param parent The root container whose children should be traversed.
545
+ * @returns An IterableIterator yielding objects with the child component and its parent container.
546
+ * @beta
547
+ */
548
+ export function* traverseTextBlockComponent(parent) {
549
+ for (const child of parent.children) {
550
+ yield { parent, child };
551
+ if (child.type === "list" || child.type === "paragraph") {
552
+ yield* traverseTextBlockComponent(child);
553
+ }
554
+ }
555
+ }
556
+ /**
557
+ * Returns the formatted marker text for a list item based on the marker type and item number.
558
+ * Supports ordered and unordered list markers, including alphabetic, Roman numeral, and numeric formats.
559
+ * @param marker The type of list marker to use.
560
+ * @param num The item number in the list.
561
+ * @returns The formatted marker string for the list item.
562
+ * @beta
563
+ */
564
+ export function getMarkerText(marker, num) {
565
+ let markerString = "";
566
+ switch (marker.enumerator) {
567
+ case undefined:
568
+ case ListMarkerEnumerator.Number:
569
+ markerString = `${num}`;
570
+ break;
571
+ case ListMarkerEnumerator.Letter:
572
+ markerString = integerToAlpha(num);
573
+ break;
574
+ case ListMarkerEnumerator.RomanNumeral:
575
+ markerString = integerToRoman(num);
576
+ break;
577
+ default:
578
+ markerString = marker.enumerator;
579
+ break;
580
+ }
581
+ if (marker.case) {
582
+ markerString = marker.case === "upper" ? markerString.toUpperCase() : markerString.toLowerCase();
583
+ }
584
+ const terminator = marker.terminator === "period" ? "." : marker.terminator === "parenthesis" ? ")" : "";
585
+ return `${markerString}${terminator}`;
586
+ }
587
+ /**
588
+ * Converts an integer to its Roman numeral representation.
589
+ * Supports numbers from 1 and above.
590
+ * @param num The integer to convert.
591
+ * @returns The Roman numeral string.
592
+ */
593
+ function integerToRoman(num) {
594
+ const values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
595
+ const symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
596
+ let roman = '';
597
+ for (let i = 0; i < values.length; i++) {
598
+ while (num >= values[i]) {
599
+ roman += symbols[i];
600
+ num -= values[i];
601
+ }
602
+ }
603
+ return roman;
604
+ }
605
+ /**
606
+ * Converts an integer to its alphabetic representation (A-Z, AA-ZZ, etc.).
607
+ * Used for ordered list markers with alphabetic styles.
608
+ * @param num The integer to convert (1-based).
609
+ * @returns The alphabetic string for the given number.
610
+ */
611
+ function integerToAlpha(num) {
612
+ const letterOffset = (num - 1) % 26;
613
+ const letter = String.fromCharCode(65 + letterOffset);
614
+ const depth = Math.ceil(num / 26);
615
+ return letter.repeat(depth);
616
+ }
501
617
  //# sourceMappingURL=TextBlock.js.map