@trebco/treb 31.3.4 → 31.7.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.
package/dist/treb.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /*! API v31.3. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
1
+ /*! API v31.7. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
2
2
 
3
3
  /**
4
4
  * add our tag to the map
@@ -498,6 +498,7 @@ export declare class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
498
498
  InsertTable(range?: RangeReference, options?: InsertTableOptions): void;
499
499
  RemoveTable(range?: RangeReference): void;
500
500
  UpdateTableStyle(range?: RangeReference, theme?: TableTheme | number): void;
501
+ SetTabColor(sheet?: number | string, color?: Color): void;
501
502
 
502
503
  /**
503
504
  * Add a sheet, optionally named.
@@ -2153,6 +2154,11 @@ export interface AnnotationChartData extends AnnotationDataBase {
2153
2154
  }
2154
2155
  export interface AnnotationTextBoxData extends AnnotationDataBase {
2155
2156
  type: 'textbox';
2157
+
2158
+ /**
2159
+ * @internalRemarks
2160
+ * what's with this weird structure? did we inherit it? can we clean it up?
2161
+ */
2156
2162
  data: {
2157
2163
  style?: CellStyle;
2158
2164
  paragraphs: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trebco/treb",
3
- "version": "31.3.4",
3
+ "version": "31.7.0",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "homepage": "https://treb.app",
6
6
  "repository": {
@@ -125,14 +125,22 @@ export const ColorFunctions = {
125
125
  ////////////////
126
126
 
127
127
 
128
- GetLuminance: (r: number, g: number, b: number): number => {
128
+ GetLuminance: ([r, g, b]: number[],): number => {
129
129
  const a = [r, g, b].map(v => {
130
130
  v /= 255;
131
131
  return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
132
132
  });
133
133
  return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
134
134
  },
135
-
135
+
136
+ WeightedLuminance: ([r, g, b]: number[], weights: number[] = [1,1,1]): number => {
137
+ const a = [r, g, b].map(v => {
138
+ v /= 255;
139
+ return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
140
+ });
141
+ return 0.2126 * a[0] * weights[0] + 0.7152 * a[1] * weights[1] + 0.0722 * a[2] * weights[2];
142
+ },
143
+
136
144
  GetContrastRatio: (data: [number, number]): number => {
137
145
  data.sort((a, b) => b - a);
138
146
  return (data[0] + 0.05) / (data[1] + 0.05);
@@ -140,14 +148,39 @@ export const ColorFunctions = {
140
148
 
141
149
  GetTextColor: (background: [number, number, number], a: [number, number, number], b: [number, number, number]) => {
142
150
 
143
- const luminance = ColorFunctions.GetLuminance(...background);
144
- const luminance_a = ColorFunctions.GetLuminance(...a);
145
- const luminance_b = ColorFunctions.GetLuminance(...b);
151
+ // weighted contrast ratio: assign more weight to the r channel.
152
+
153
+ const weights = [0.4, 0.3, 0.3];
154
+
155
+ const luminance = ColorFunctions.WeightedLuminance(background, weights);
156
+ const luminance_a = ColorFunctions.WeightedLuminance(a, weights);
157
+ const luminance_b = ColorFunctions.WeightedLuminance(b, weights);
146
158
 
147
159
  const contrast_a = ColorFunctions.GetContrastRatio([luminance_a, luminance]);
148
160
  const contrast_b = ColorFunctions.GetContrastRatio([luminance_b, luminance]);
149
161
 
150
162
  return contrast_a > contrast_b ? a : b;
163
+
164
+ // perceptual lightness (actually I like this one)
165
+
166
+ /*
167
+ const background_lightness = ColorFunctions.RGBToHSL(...background).l;
168
+ const a_lightness = ColorFunctions.RGBToHSL(...a).l;
169
+ const b_lightness = ColorFunctions.RGBToHSL(...b).l;
170
+
171
+ console.info("background", background_lightness, "a", a_lightness, "b", b_lightness);
172
+
173
+ const lighter = a_lightness > b_lightness ? a : b;
174
+ const darker = a_lightness > b_lightness ? b : a;
175
+
176
+ if (background_lightness < .6) {
177
+ return lighter;
178
+ }
179
+ else {
180
+ return darker;
181
+ }
182
+ */
183
+
151
184
  },
152
185
 
153
186
  };
@@ -21,7 +21,7 @@
21
21
 
22
22
  import { UA } from 'treb-grid';
23
23
  import { Measurement } from 'treb-utils';
24
- import { type FontSize, Style } from './style';
24
+ import { Style, type FontSize } from './style';
25
25
 
26
26
  /**
27
27
  * these are the stacks we're currently supporting.
@@ -37,6 +37,15 @@ import { Color } from './vertex';
37
37
  * FIXME: it might be better to have an intermediate class/interface and
38
38
  * have both leaf- and spreadsheet-vertex extend that.
39
39
  *
40
+ * UPDATE: we're removing the internal "state" representation because (1)
41
+ * it should be unnecessary, if we are only updating when dependencies
42
+ * change, and (2) it was broken anyway.
43
+ *
44
+ * Now we rely on the calculation graph to indicate when the leaf is
45
+ * dirty and needs to update. This will result in extra calculation when
46
+ * you do a hard recalc, but that seems reasonable (and we could possibly
47
+ * work around that).
48
+ *
40
49
  */
41
50
  export class StateLeafVertex extends SpreadsheetVertex {
42
51
 
@@ -54,42 +63,6 @@ export class StateLeafVertex extends SpreadsheetVertex {
54
63
  */
55
64
  public color = Color.black;
56
65
 
57
- protected state_representation = '';
58
-
59
- /**
60
- * construct the state, compare, and increment the state id if
61
- * it changes. this is expected to be called from Calculate(), but
62
- * we can also call it on init if we already know the state.
63
- *
64
- * FIXME: what's more expensive, generating this state field or
65
- * re-rendering a chart with the same data? (...?)
66
- * especially since it's only called on dirty...
67
- *
68
- * what is the case where the depenendency is dirty but state
69
- * does not change? you type in the same value? (...) or maybe
70
- * there's a volatile function that doesn't change value (e.g. Today())
71
- *
72
- * still, it seems like a waste here. let's test without the state.
73
- * (meaning just update the flag anytime it's dirty)
74
- *
75
- * Actually I think the case is manual recalc, when values don't change
76
- * (especially true for MC charts).
77
- *
78
- * TODO: perf
79
- */
80
- public UpdateState(): void {
81
-
82
- // FIXME: hash!
83
- //const state = JSON.stringify(this.edges_in.map((edge) => (edge as SpreadsheetVertex).result));
84
- const state = JSON.stringify(Array.from(this.edges_in).map((edge) => (edge as SpreadsheetVertex).result));
85
-
86
- if (state !== this.state_representation) {
87
- this.state_representation = state;
88
- this.state_id++;
89
- }
90
-
91
- }
92
-
93
66
  /** overrides calculate function */
94
67
  public Calculate(): void {
95
68
 
@@ -103,11 +76,15 @@ export class StateLeafVertex extends SpreadsheetVertex {
103
76
  }
104
77
  }
105
78
 
106
- // ok, we can evaluate... all we are doing here is checking state consistency
107
- this.UpdateState();
79
+ // ok update state so clients know they need to refresh
80
+ // (see note above re: internal state)
81
+
82
+ this.state_id++;
83
+
84
+ // and we're clean
85
+
108
86
  this.dirty = false;
109
87
 
110
- // we are not allowed to have edges out, so nothing to do
111
88
  }
112
89
 
113
90
  public AddDependent(): void {
@@ -190,6 +190,11 @@ export interface AnnotationChartData extends AnnotationDataBase {
190
190
 
191
191
  export interface AnnotationTextBoxData extends AnnotationDataBase {
192
192
  type: 'textbox';
193
+
194
+ /**
195
+ * @internalRemarks
196
+ * what's with this weird structure? did we inherit it? can we clean it up?
197
+ */
193
198
  data: {
194
199
  style?: CellStyle;
195
200
  paragraphs: {
@@ -1411,18 +1411,25 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1411
1411
  if (event.type === 'structure') {
1412
1412
  this.grid.EnsureActiveSheet();
1413
1413
  this.grid.UpdateLayout();
1414
- // (this.grid as any).tab_bar?.Update();
1415
1414
  this.grid.UpdateTabBar();
1415
+
1416
+ if (event.update_annotations) {
1417
+ this.grid.RefreshAnnotations();
1418
+ this.InflateAnnotations();
1419
+ }
1420
+
1416
1421
  }
1417
1422
  });
1418
1423
 
1419
1424
  view.Subscribe(event => {
1425
+
1420
1426
  switch (event.type) {
1421
1427
  case 'selection':
1422
1428
  break;
1423
1429
  default:
1424
1430
  view.UpdateAnnotations();
1425
1431
  this.grid.Update(true);
1432
+ this.grid.UpdateAnnotations();
1426
1433
  }
1427
1434
  });
1428
1435
 
@@ -1430,8 +1437,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1430
1437
  if (event.type === 'structure') {
1431
1438
  view.grid.EnsureActiveSheet();
1432
1439
  view.grid.UpdateLayout();
1433
- // (view.grid as any).tab_bar?.Update();
1434
1440
  view.grid.UpdateTabBar();
1441
+
1442
+ if (event.update_annotations) {
1443
+ view.grid.RefreshAnnotations();
1444
+ view.InflateAnnotations();
1445
+ }
1446
+
1435
1447
  }
1436
1448
  });
1437
1449
 
@@ -1444,12 +1456,14 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1444
1456
  case 'reset':
1445
1457
  view.grid.EnsureActiveSheet(true); // force update of annotations
1446
1458
  view.UpdateAnnotations();
1459
+ view.grid.UpdateAnnotations();
1447
1460
  view.grid.Update(true);
1448
1461
  break;
1449
1462
 
1450
1463
  default:
1451
1464
  view.UpdateAnnotations();
1452
1465
  view.grid.Update(true);
1466
+ view.grid.UpdateAnnotations();
1453
1467
  }
1454
1468
  });
1455
1469
 
@@ -1651,7 +1665,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1651
1665
  if (selection && !selection.empty) {
1652
1666
  const label = selection.area.spreadsheet_label;
1653
1667
 
1654
- if (func === 'Scatter.Plot' || func === 'Scatter.Line') {
1668
+ if (func === 'Scatter.Plot' || func === 'Scatter.Line' || func === 'Box.Plot') {
1655
1669
  this.InsertAnnotation(`=${func}(Series(,,${label}),"${label}")`, undefined, undefined, ',');
1656
1670
  }
1657
1671
  else {
@@ -1758,8 +1772,6 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1758
1772
 
1759
1773
  if (scale && !isNaN(scale)) {
1760
1774
 
1761
- console.info("FS", scale);
1762
-
1763
1775
  this.grid.ApplyStyle(undefined, {
1764
1776
  //font_size_unit: 'em', font_size_value: scale
1765
1777
  font_size: {
@@ -1843,6 +1855,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1843
1855
  case 'insert-bar-chart': insert_annotation('Bar.Chart'); break;
1844
1856
  case 'insert-line-chart': insert_annotation('Line.Chart'); break;
1845
1857
  case 'insert-scatter-plot': insert_annotation('Scatter.Plot'); break;
1858
+ case 'insert-box-plot': insert_annotation('Box.Plot'); break;
1846
1859
 
1847
1860
  case 'increase-precision':
1848
1861
  case 'decrease-precision':
@@ -2230,12 +2243,22 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2230
2243
  // FIXME: sheet change events (affects annotations)
2231
2244
  // TODO: sheet change events (affects annotations)
2232
2245
 
2246
+ // console.info({events});
2247
+
2233
2248
  for (const event of events) {
2234
- if (event.type === 'data') {
2235
- recalc = true;
2236
- }
2237
- else if (event.type === 'structure') {
2238
- if (event.rebuild_required) reset = true;
2249
+ switch (event.type) {
2250
+ case 'data':
2251
+ recalc = true;
2252
+ break;
2253
+
2254
+ case 'structure':
2255
+ if (event.rebuild_required) {
2256
+ reset = true;
2257
+ }
2258
+ break;
2259
+
2260
+ default:
2261
+ // console.info('unhandled event:', event.type, { event });
2239
2262
  }
2240
2263
  }
2241
2264
 
@@ -2417,6 +2440,17 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2417
2440
 
2418
2441
  }
2419
2442
 
2443
+ public SetTabColor(sheet?: number|string, color?: Color) {
2444
+ const target = (typeof sheet === 'undefined') ?
2445
+ this.grid.active_sheet :
2446
+ this.model.sheets.Find(sheet);
2447
+
2448
+ if (target) {
2449
+ this.grid.TabColor(target, color);
2450
+ }
2451
+
2452
+ }
2453
+
2420
2454
  /**
2421
2455
  * Add a sheet, optionally named.
2422
2456
  */
@@ -2585,9 +2619,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2585
2619
  * the argument separator, we allow that to be passed directly, but this
2586
2620
  * is deprecated. new code should use the options object.
2587
2621
  */
2588
- public InsertAnnotation(formula: string, type: AnnotationType = 'treb-chart', rect?: IRectangle|RangeReference, options?: EvaluateOptions|','|';'): void {
2622
+ public InsertAnnotation(
2623
+ formula: string,
2624
+ type: AnnotationType = 'treb-chart',
2625
+ rect?: IRectangle|RangeReference,
2626
+ options?: EvaluateOptions|','|';'): void {
2589
2627
 
2590
- let target: IRectangle | Partial<Area> | undefined;
2628
+ let target: IRectangle | IArea | undefined;
2591
2629
  let argument_separator: ','|';'|undefined = undefined;
2592
2630
  let r1c1 = false;
2593
2631
 
@@ -2664,7 +2702,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2664
2702
  type,
2665
2703
  formula,
2666
2704
  // class_name,
2667
- }, undefined, undefined, target || { top: y / scale + 30, left: x / scale + 30, ...auto_size });
2705
+ }, undefined, undefined, undefined, target || { top: y / scale + 30, left: x / scale + 30, ...auto_size });
2668
2706
 
2669
2707
  }
2670
2708
 
@@ -5353,7 +5391,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
5353
5391
  src: contents,
5354
5392
  original_size: { width: img.width || 300, height: img.height || 300 },
5355
5393
  },
5356
- }, undefined, undefined, {
5394
+ }, undefined, undefined, undefined, {
5357
5395
  top: 30,
5358
5396
  left: 30,
5359
5397
  width: img.width || 300,
@@ -5488,7 +5526,17 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
5488
5526
 
5489
5527
  // set all views dirty in this case
5490
5528
  for (const view of annotation.view) {
5491
- view.dirty = true;
5529
+
5530
+ // if !view, that usually means it was just created. it should
5531
+ // get taken care of soon, so don't worry about it.
5532
+
5533
+ if (view) {
5534
+ view.dirty = true;
5535
+ }
5536
+ // else {
5537
+ // console.info("empty view")
5538
+ // }
5539
+
5492
5540
  }
5493
5541
  }
5494
5542
 
@@ -5508,6 +5556,8 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
5508
5556
  // either we just set this dirty for all views, or another
5509
5557
  // view set it dirty for us: in either case, update
5510
5558
 
5559
+ view.dirty = false;
5560
+
5511
5561
  if (view.update_callback) {
5512
5562
  view.update_callback();
5513
5563
  }
@@ -23,7 +23,7 @@ export interface BorderToolbarMessage {
23
23
  }
24
24
 
25
25
  export interface AnnotationToolbarMessage {
26
- command: 'insert-image'|'insert-donut-chart'|'insert-line-chart'|'insert-column-chart'|'insert-bar-chart'|'insert-scatter-plot';
26
+ command: 'insert-image'|'insert-donut-chart'|'insert-line-chart'|'insert-column-chart'|'insert-bar-chart'|'insert-scatter-plot'|'insert-box-plot';
27
27
  }
28
28
 
29
29
  export interface LayoutToolbarMessage {
@@ -104,7 +104,9 @@ import type {
104
104
  InsertRowsCommand, InsertColumnsCommand, SetNameCommand,
105
105
  ActivateSheetCommand, DataValidationCommand,
106
106
  ResizeRowsCommand, ResizeColumnsCommand,
107
- SelectCommand
107
+ SelectCommand,
108
+ CreateAnnotationCommand,
109
+ RemoveAnnotationCommand
108
110
  } from './grid_command';
109
111
  import { CommandKey
110
112
  } from './grid_command';
@@ -705,6 +707,26 @@ export class Grid extends GridBase {
705
707
  return undefined;
706
708
  }
707
709
 
710
+ public CreateAnnotation(
711
+ properties: Partial<AnnotationData> = {},
712
+ sheet: Sheet = this.active_sheet,
713
+ add_to_sheet = true,
714
+ offset = false,
715
+ target?: IArea|IRectangle,
716
+ focus?: boolean ) {
717
+
718
+ this.ExecCommand({
719
+ key: CommandKey.CreateAnnotation,
720
+ properties,
721
+ add_to_sheet,
722
+ offset,
723
+ target,
724
+ focus,
725
+ sheet,
726
+ });
727
+
728
+ }
729
+
708
730
  /**
709
731
  * create an annotation, with properties, without an original object.
710
732
  * optionally (and by default) add to sheet.
@@ -716,10 +738,11 @@ export class Grid extends GridBase {
716
738
  * @param target new parameter allows setting annotation as rect or as
717
739
  * cell range
718
740
  */
719
- public CreateAnnotation(properties: Partial<AnnotationData> = {}, add_to_sheet = true, offset = false, target?: Partial<Area>|IRectangle): Annotation {
720
- const annotation = new Annotation(properties);
741
+ protected CreateAnnotationInternal(command: CreateAnnotationCommand) {
721
742
 
722
- if (offset) {
743
+ const annotation = new Annotation(command.properties);
744
+
745
+ if (command.offset) {
723
746
 
724
747
  // to offset, we have to have layout (or at least scaled rect)
725
748
  if (!annotation.data.layout && annotation.scaled_rect) {
@@ -734,7 +757,7 @@ export class Grid extends GridBase {
734
757
  let recheck = true;
735
758
  while (recheck) {
736
759
  recheck = false;
737
- for (const test of this.active_sheet.annotations) {
760
+ for (const test of command.sheet.annotations) {
738
761
  if (test === annotation) { continue; }
739
762
  if (test.scaled_rect && test.scaled_rect.top === target_rect.top && test.scaled_rect.left === target_rect.left) {
740
763
  target_rect = target_rect.Shift(20, 20);
@@ -747,28 +770,44 @@ export class Grid extends GridBase {
747
770
  }
748
771
  }
749
772
 
750
- if (target) {
751
- if (Rectangle.IsRectangle(target)) {
773
+ if (command.target) {
774
+ if (Rectangle.IsRectangle(command.target)) {
752
775
  // console.info('creating from rectangle,', target);
753
776
  annotation.data.layout = undefined;
754
- annotation.rect = Rectangle.Create(target);
777
+ annotation.rect = Rectangle.Create(command.target);
755
778
  }
756
- else if (target.start) {
779
+ else if (command.target.start) {
757
780
  annotation.rect = undefined;
758
- annotation.data.layout = this.layout.AddressToAnnotationLayout(target.start, target.end||target.start);
781
+ annotation.data.layout = this.layout.AddressToAnnotationLayout(command.target.start, command.target.end||command.target.start);
759
782
  }
760
783
  }
761
784
 
762
- if (add_to_sheet) {
785
+ if (command.add_to_sheet) {
763
786
 
764
787
  // ensure we haven't already added this
765
- if (!this.active_sheet.annotations.some((test) => test === annotation)) {
766
- this.active_sheet.annotations.push(annotation);
788
+ if (!command.sheet.annotations.some((test) => test === annotation)) {
789
+ command.sheet.annotations.push(annotation);
767
790
  }
768
791
 
769
792
  this.AddAnnotation(annotation);
770
793
  }
771
- return annotation;
794
+
795
+ if (command.focus) {
796
+
797
+ // pending... we need to know which view it was pasted in. maybe this
798
+ // should be the index?
799
+
800
+ const view = annotation.view[this.view_index];
801
+ if (view && view.node) {
802
+ const node = view.node;
803
+ setTimeout(() => {
804
+ node.focus();
805
+ }, 1);
806
+ }
807
+
808
+ }
809
+
810
+ // return annotation;
772
811
  }
773
812
 
774
813
  /** placeholder */
@@ -1060,21 +1099,17 @@ export class Grid extends GridBase {
1060
1099
  * the parent (although the node still exists in the annotation, if
1061
1100
  * it existed before).
1062
1101
  */
1063
- public RemoveAnnotation(annotation: Annotation): void {
1064
- for (let i = 0; i < this.active_sheet.annotations.length; i++) {
1065
- if (annotation === this.active_sheet.annotations[i]) {
1066
- this.active_sheet.annotations.splice(i, 1);
1067
-
1068
- this.layout.RemoveAnnotation(annotation);
1102
+ public RemoveAnnotation(annotation: Annotation, sheet = this.active_sheet): void {
1103
+ this.ExecCommand({
1104
+ key: CommandKey.RemoveAnnotation,
1105
+ annotation,
1106
+ sheet,
1107
+ });
1108
+ }
1069
1109
 
1070
- this.grid_events.Publish({
1071
- type: 'annotation',
1072
- annotation,
1073
- event: 'delete',
1074
- });
1075
- return;
1076
- }
1077
- }
1110
+ protected RemoveAnnotationInternal(command: RemoveAnnotationCommand) {
1111
+ super.RemoveAnnotationInternal(command);
1112
+ this.layout.RemoveAnnotation(command.annotation);
1078
1113
  }
1079
1114
 
1080
1115
  /**
@@ -1474,6 +1509,18 @@ export class Grid extends GridBase {
1474
1509
 
1475
1510
  }
1476
1511
 
1512
+ /** set scale directly */
1513
+ public SetScale(scale: number) {
1514
+ scale = Math.round(scale * 1000) / 1000;
1515
+ scale = Math.min(2, Math.max(scale, .5));
1516
+
1517
+ if (this.options.persist_scale_key) {
1518
+ localStorage.setItem(this.options.persist_scale_key, JSON.stringify({scale}));
1519
+ }
1520
+
1521
+ this.scale = scale;
1522
+ }
1523
+
1477
1524
  /**
1478
1525
  * @param container html container element
1479
1526
  */
@@ -2430,6 +2477,15 @@ export class Grid extends GridBase {
2430
2477
  this.DelayedRender(force, area);
2431
2478
  }
2432
2479
 
2480
+ /**
2481
+ * update annotation layouts (not content)
2482
+ */
2483
+ public UpdateAnnotations() {
2484
+ if (this.active_sheet.annotations.length) {
2485
+ this.layout.UpdateAnnotation(this.active_sheet.annotations, this.theme);
2486
+ }
2487
+ }
2488
+
2433
2489
  /* *
2434
2490
  * API method
2435
2491
  *
@@ -2676,6 +2732,18 @@ export class Grid extends GridBase {
2676
2732
 
2677
2733
  }
2678
2734
 
2735
+ /**
2736
+ * this is intended to synchronize views when annotations are added/removed.
2737
+ * there should be no need to call it if there's only one view.
2738
+ */
2739
+ public RefreshAnnotations() {
2740
+
2741
+ this.RemoveAnnotationNodes();
2742
+ for (const element of this.active_sheet.annotations) {
2743
+ this.AddAnnotation(element, true, true);
2744
+ }
2745
+
2746
+ }
2679
2747
 
2680
2748
  /**
2681
2749
  * specialization for grid. note that we don't call superclass,
@@ -3934,7 +4002,14 @@ export class Grid extends GridBase {
3934
4002
  if (cell?.note) {
3935
4003
 
3936
4004
  // optional MD formatting
3937
- const md = this.options.markdown ? MDParser.instance.HTML(MDParser.instance.Parse(cell.note)) : undefined;
4005
+
4006
+ // UPDATE: we should allow MD in notes irrespective of the cell
4007
+ // markdown setting. or maybe split the two settings? it makes
4008
+ // a lot of sense in comments, even if you don't want it in cells.
4009
+
4010
+ const parsed = MDParser.instance.Parse(cell.note);
4011
+
4012
+ const md = this.options.comment_markdown ? MDParser.instance.HTML(parsed, { br: false }) : undefined;
3938
4013
  this.layout.ShowNote(cell.note, address, event, md);
3939
4014
 
3940
4015
  this.hover_data.note = true;
@@ -5399,7 +5474,7 @@ export class Grid extends GridBase {
5399
5474
  */
5400
5475
  private SetInferredType(selection: GridSelection, value: string|undefined, array = false, exec = true, apply_style?: CellStyle) {
5401
5476
 
5402
- console.info("SIT", {apply_style});
5477
+ // console.info("SIT", {apply_style});
5403
5478
 
5404
5479
  // validation: cannot change part of an array without changing the
5405
5480
  // whole array. so check the array. separately, if you are entering
@@ -7285,6 +7360,9 @@ export class Grid extends GridBase {
7285
7360
  }
7286
7361
  }
7287
7362
  }
7363
+
7364
+ this.CreateAnnotation(composite.data, undefined, true, true, undefined, true);
7365
+ /*
7288
7366
  const annotation = this.CreateAnnotation(composite.data, true, true);
7289
7367
  const view = annotation.view[this.view_index];
7290
7368
  if (view && view.node) {
@@ -7293,6 +7371,7 @@ export class Grid extends GridBase {
7293
7371
  node.focus();
7294
7372
  }, 1);
7295
7373
  }
7374
+ */
7296
7375
  }
7297
7376
  catch (e) {
7298
7377
  console.error(e);