@trebco/treb 27.12.2 → 28.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +6 -0
  2. package/dist/treb-spreadsheet-light.mjs +16 -0
  3. package/dist/treb-spreadsheet.mjs +13 -11
  4. package/dist/treb.d.ts +33 -5
  5. package/esbuild-custom-element.mjs +3 -1
  6. package/package.json +8 -6
  7. package/treb-base-types/src/dom-utilities.ts +157 -19
  8. package/treb-base-types/src/import.ts +1 -0
  9. package/treb-base-types/src/theme.ts +5 -4
  10. package/treb-charts/src/renderer.ts +4 -58
  11. package/treb-embed/markup/layout.html +4 -0
  12. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +131 -87
  13. package/treb-embed/src/embedded-spreadsheet.ts +153 -140
  14. package/treb-embed/src/options.ts +9 -0
  15. package/treb-embed/src/spinner.ts +5 -3
  16. package/treb-embed/src/toolbar-message.ts +5 -0
  17. package/treb-embed/style/layout.scss +65 -1
  18. package/treb-export/src/export-worker/export-worker.ts +7 -12
  19. package/treb-export/src/export2.ts +57 -33
  20. package/treb-export/src/import2.ts +61 -21
  21. package/treb-export/src/workbook2.ts +69 -24
  22. package/treb-export/src/zip-wrapper.ts +96 -0
  23. package/treb-grid/src/editors/autocomplete.ts +24 -13
  24. package/treb-grid/src/editors/editor.ts +43 -139
  25. package/treb-grid/src/editors/external_editor.ts +1 -1
  26. package/treb-grid/src/editors/formula_bar.ts +24 -24
  27. package/treb-grid/src/editors/overlay_editor.ts +1 -1
  28. package/treb-grid/src/layout/base_layout.ts +34 -25
  29. package/treb-grid/src/layout/grid_layout.ts +20 -20
  30. package/treb-grid/src/render/selection-renderer.ts +3 -3
  31. package/treb-grid/src/render/svg_header_overlay.ts +6 -4
  32. package/treb-grid/src/render/svg_selection_block.ts +10 -7
  33. package/treb-grid/src/types/annotation.ts +2 -2
  34. package/treb-grid/src/types/grid.ts +80 -81
  35. package/treb-grid/src/types/scale-control.ts +69 -81
  36. package/treb-grid/src/types/sheet.ts +3 -52
  37. package/treb-grid/src/types/tab_bar.ts +27 -13
  38. package/treb-grid/src/util/fontmetrics2.ts +24 -21
  39. package/treb-utils/src/event_source.ts +23 -23
  40. package/treb-utils/src/index.ts +2 -2
  41. package/treb-utils/src/measurement.ts +24 -24
  42. package/treb-utils/src/serialize_html.ts +25 -21
  43. package/treb-utils/src/dispatch.ts +0 -57
  44. package/treb-utils/src/resizable.ts +0 -159
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import { DOMUtilities } from 'treb-base-types';
22
+ import { DOMContext } from 'treb-base-types';
23
23
  import type { DataModel, ViewModel } from '../types/data_model';
24
24
 
25
25
  import type { Tile } from '../types/tile';
@@ -185,12 +185,16 @@ export abstract class BaseLayout {
185
185
  private initialized = false;
186
186
 
187
187
 
188
- constructor(protected model: DataModel, protected view: ViewModel, mock = false) {
188
+ constructor(protected model: DataModel, protected view: ViewModel, mock = false, public DOM = DOMContext.GetInstance()) {
189
189
 
190
190
  if (mock) {
191
191
  return;
192
192
  }
193
193
 
194
+ if (!DOM) {
195
+ throw new Error('missing DOM context');
196
+ }
197
+
194
198
  this.dpr = Math.max(1, self.devicePixelRatio || 1);
195
199
 
196
200
  // now attaching to node... no longer global
@@ -201,16 +205,14 @@ export abstract class BaseLayout {
201
205
  // contexts; the mask will be under the next sheet. so either
202
206
  // global in body, or instance local.
203
207
 
204
- this.mask = DOMUtilities.Div('treb-mouse-mask');
205
- this.tooltip = DOMUtilities.Div('treb-tooltip');
208
+ this.mask = DOM.Div('treb-mouse-mask');
209
+ this.tooltip = DOM.Div('treb-tooltip');
206
210
 
207
- // this.error_highlight = DOMUtilities.CreateDiv('treb-error-highlight');
208
-
209
- this.dropdown_caret = DOMUtilities.SVG('svg', 'treb-dropdown-caret');
211
+ this.dropdown_caret = DOM.SVG('svg', 'treb-dropdown-caret');
210
212
  this.dropdown_caret.setAttribute('viewBox', '0 0 24 24');
211
213
  this.dropdown_caret.tabIndex = -1;
212
214
 
213
- const caret =DOMUtilities.SVG('path');
215
+ const caret = DOM.SVG('path');
214
216
  caret.setAttribute('d', 'M5,7 L12,17 L19,7');
215
217
  this.dropdown_caret.appendChild(caret);
216
218
 
@@ -247,8 +249,10 @@ export abstract class BaseLayout {
247
249
  });
248
250
  */
249
251
 
250
- this.dropdown_list = DOMUtilities.Div('treb-dropdown-list');
251
- this.dropdown_list.setAttribute('tabindex', '-1'); // focusable
252
+ this.dropdown_list = DOM.Div('treb-dropdown-list', undefined, {
253
+ attrs: { tabindex: '-1' },
254
+ });
255
+ // this.dropdown_list.setAttribute('tabindex', '-1'); // focusable
252
256
 
253
257
  // this.dropdown_caret.addEventListener('keydown', (event) => {
254
258
  this.dropdown_list.addEventListener('keydown', (event) => {
@@ -346,15 +350,17 @@ export abstract class BaseLayout {
346
350
  this.dropdown_selected = target as HTMLElement;
347
351
  });
348
352
 
349
- this.mock_selection = DOMUtilities.Div('mock-selection-node');
350
- this.mock_selection.innerHTML = ' ';
353
+ this.mock_selection = DOM.Div('mock-selection-node', undefined, {
354
+ html: ' ',
355
+ });
356
+ // this.mock_selection.innerHTML = ' ';
351
357
 
352
- this.note_node = DOMUtilities.Div('treb-note');
353
- this.title_node = DOMUtilities.Div('treb-hover-title');
358
+ this.note_node = DOM.Div('treb-note');
359
+ this.title_node = DOM.Div('treb-hover-title');
354
360
 
355
- this.sort_button = DOMUtilities.Create(
361
+ this.sort_button = DOM.Create(
356
362
  'button',
357
- 'treb-sort-button', undefined, undefined, { title: 'Sort table', tabindex: '-1'});
363
+ 'treb-sort-button', undefined, { attrs: { title: 'Sort table', tabindex: '-1' }});
358
364
 
359
365
  this.HideNote();
360
366
 
@@ -1167,15 +1173,18 @@ export abstract class BaseLayout {
1167
1173
 
1168
1174
  // FIXME: limit to edge (causing problems in chrome? ...)
1169
1175
 
1170
- const selection = window.getSelection();
1176
+ if (this.DOM.doc) {
1177
+
1178
+ const selection = this.DOM.GetSelection();
1171
1179
 
1172
- if (selection) {
1173
- const range = document.createRange();
1174
- range.selectNodeContents(this.mock_selection);
1175
- selection.removeAllRanges();
1176
- selection.addRange(range);
1180
+ if (selection) {
1181
+ const range = this.DOM.doc.createRange();
1182
+ range.selectNodeContents(this.mock_selection);
1183
+ selection.removeAllRanges();
1184
+ selection.addRange(range);
1185
+
1186
+ }
1177
1187
 
1178
- // selection.collapseToEnd();
1179
1188
  }
1180
1189
 
1181
1190
  }
@@ -1194,7 +1203,7 @@ export abstract class BaseLayout {
1194
1203
  parent: HTMLElement,
1195
1204
  mark_dirty = true): Tile {
1196
1205
 
1197
- const tile = DOMUtilities.Create('canvas') as Tile;
1206
+ const tile = this.DOM.Create('canvas') as Tile;
1198
1207
  tile.setAttribute('class', classes);
1199
1208
  tile.logical_size = size;
1200
1209
  tile.width = size.width * this.dpr;
@@ -1403,7 +1412,7 @@ export abstract class BaseLayout {
1403
1412
 
1404
1413
  this.dropdown_list.textContent = '';
1405
1414
  for (const value of list) {
1406
- const entry = DOMUtilities.Div(undefined, this.dropdown_list);
1415
+ const entry = this.DOM.Div(undefined, this.dropdown_list);
1407
1416
  if (current === value) {
1408
1417
  this.dropdown_selected = entry;
1409
1418
  entry.classList.add('selected');
@@ -21,7 +21,7 @@
21
21
 
22
22
  import { BaseLayout } from './base_layout';
23
23
  import type { Tile } from '../types/tile';
24
- import { DOMUtilities } from 'treb-base-types';
24
+ import { DOMContext } from 'treb-base-types';
25
25
  import type { DataModel, ViewModel } from '../types/data_model';
26
26
 
27
27
 
@@ -32,8 +32,8 @@ import type { DataModel, ViewModel } from '../types/data_model';
32
32
  */
33
33
  export class GridLayout extends BaseLayout {
34
34
 
35
- constructor(model: DataModel, view: ViewModel){
36
- super(model, view);
35
+ constructor(model: DataModel, view: ViewModel, DOM: DOMContext){
36
+ super(model, view, false, DOM);
37
37
 
38
38
  // nodes always exist
39
39
 
@@ -41,37 +41,37 @@ export class GridLayout extends BaseLayout {
41
41
  // mask needs to get attached to a container, when it's
42
42
  // available
43
43
 
44
- this.column_header = DOMUtilities.Div('treb-top-header');
45
- this.row_header = DOMUtilities.Div('treb-left-header');
44
+ this.column_header = DOM.Div('treb-top-header');
45
+ this.row_header = DOM.Div('treb-left-header');
46
46
 
47
- this.corner = DOMUtilities.Div('treb-corner');
48
- this.corner_canvas = DOMUtilities.Create('canvas');
47
+ this.corner = DOM.Div('treb-corner');
48
+ this.corner_canvas = DOM.Create('canvas');
49
49
  this.corner.appendChild(this.corner_canvas);
50
50
 
51
- this.contents = DOMUtilities.Div('treb-contents');
52
- this.buffer_canvas = DOMUtilities.Create('canvas', 'treb-buffer-canvas', this.contents);
51
+ this.contents = DOM.Div('treb-contents');
52
+ this.buffer_canvas = DOM.Create('canvas', 'treb-buffer-canvas', this.contents);
53
53
 
54
54
  // selection node attached to contents
55
- this.grid_selection = DOMUtilities.SVG('svg', 'treb-grid-selection', this.contents);
55
+ this.grid_selection = DOM.SVG('svg', 'treb-grid-selection', this.contents);
56
56
 
57
57
  // selection node for frozen rows
58
- this.row_header_selection = DOMUtilities.SVG('svg', ['frozen-selection', 'frozen-selection-rows'], this.column_header);
59
- this.row_header_annotations = DOMUtilities.Div('frozen-annotation-container frozen-annotation-container-rows', this.column_header);
58
+ this.row_header_selection = DOM.SVG('svg', ['frozen-selection', 'frozen-selection-rows'], this.column_header);
59
+ this.row_header_annotations = DOM.Div('frozen-annotation-container frozen-annotation-container-rows', this.column_header);
60
60
 
61
61
  // ...columns
62
- this.column_header_selection = DOMUtilities.SVG('svg', ['frozen-selection', 'frozen-selection-columns'], this.row_header);
63
- this.column_header_annotations = DOMUtilities.Div('frozen-annotation-container frozen-annotation-container-columns', this.row_header);
62
+ this.column_header_selection = DOM.SVG('svg', ['frozen-selection', 'frozen-selection-columns'], this.row_header);
63
+ this.column_header_annotations = DOM.Div('frozen-annotation-container frozen-annotation-container-columns', this.row_header);
64
64
 
65
65
  // ...corner
66
- this.corner_selection = DOMUtilities.SVG('svg', 'frozen-selection', this.corner);
67
- this.corner_annotations = DOMUtilities.Div('frozen-annotation-container frozen-annotation-container-corner', this.corner);
66
+ this.corner_selection = DOM.SVG('svg', 'frozen-selection', this.corner);
67
+ this.corner_annotations = DOM.Div('frozen-annotation-container frozen-annotation-container-corner', this.corner);
68
68
 
69
69
 
70
- this.annotation_container = DOMUtilities.Div('treb-annotation-container');
70
+ this.annotation_container = DOM.Div('treb-annotation-container');
71
71
 
72
- this.grid_cover = DOMUtilities.Div('tile-cover grid-cover');
73
- this.column_header_cover = DOMUtilities.Div('tile-cover column-header-cover');
74
- this.row_header_cover = DOMUtilities.Div('tile-cover row-header-cover');
72
+ this.grid_cover = DOM.Div('tile-cover grid-cover');
73
+ this.column_header_cover = DOM.Div('tile-cover column-header-cover');
74
+ this.row_header_cover = DOM.Div('tile-cover row-header-cover');
75
75
 
76
76
  }
77
77
 
@@ -20,7 +20,7 @@
20
20
  */
21
21
 
22
22
  import type { Theme, ICellAddress } from 'treb-base-types';
23
- import { DOMUtilities, Rectangle } from 'treb-base-types';
23
+ import { DOMContext, Rectangle } from 'treb-base-types';
24
24
  import type { BaseLayout } from '../layout/base_layout';
25
25
  import type { SelectionOffset } from './svg_selection_block';
26
26
  import { SVGSelectionBlock } from './svg_selection_block';
@@ -289,7 +289,7 @@ export class SelectionRenderer {
289
289
 
290
290
  let selection_block: SVGSelectionBlock = node_set[index];
291
291
  if (!selection_block) {
292
- selection_block = new SVGSelectionBlock(!index, this.theme);
292
+ selection_block = new SVGSelectionBlock(!index, this.theme, undefined, node);
293
293
  node_set[index] = selection_block;
294
294
 
295
295
  if (index) {
@@ -302,7 +302,7 @@ export class SelectionRenderer {
302
302
 
303
303
  let group: SVGElement = node.querySelector('.alternate-selections') as SVGElement;
304
304
  if (!group) {
305
- group = DOMUtilities.SVG('g', 'alternate-selections');
305
+ group = this.layout.DOM.SVG('g', 'alternate-selections');
306
306
  node.appendChild(group);
307
307
  }
308
308
  group?.appendChild(selection_block.g);
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import { DOMUtilities, type Theme } from 'treb-base-types';
22
+ import { DOMContext, type Theme } from 'treb-base-types';
23
23
 
24
24
  export enum Orientation {
25
25
  Horizontal,
@@ -37,9 +37,11 @@ export class HeaderOverlay {
37
37
  private container: SVGElement,
38
38
  private orientation: Orientation) {
39
39
 
40
- this.g = DOMUtilities.SVG('g', 'treb-header-overlay');
41
- this.overlay = DOMUtilities.SVG('rect', 'treb-overlay');
42
- this.highlight = DOMUtilities.SVG('rect', 'treb-highlight');
40
+ const DOM = DOMContext.GetInstance(container.ownerDocument);
41
+
42
+ this.g = DOM.SVG('g', 'treb-header-overlay');
43
+ this.overlay = DOM.SVG('rect', 'treb-overlay');
44
+ this.highlight = DOM.SVG('rect', 'treb-highlight');
43
45
 
44
46
  this.g.style.display = 'none';
45
47
  this.g.appendChild(this.highlight);
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import { type Theme, type Rectangle, DOMUtilities } from 'treb-base-types';
22
+ import { type Theme, type Rectangle, DOMContext } from 'treb-base-types';
23
23
 
24
24
  /**
25
25
  * the original selections -- a canvas overlaid over the tile canvases --
@@ -44,12 +44,15 @@ export class SVGSelectionBlock {
44
44
 
45
45
  constructor( primary: boolean,
46
46
  private theme: Theme,
47
- private offset: SelectionOffset = {x: 0, y: 0}) {
47
+ private offset: SelectionOffset = {x: 0, y: 0},
48
+ node: SVGElement) {
48
49
 
49
- this.g = DOMUtilities.SVG('g');
50
+ const DOM = DOMContext.GetInstance(node.ownerDocument);
51
+
52
+ this.g = DOM.SVG('g');
50
53
  this.g.setAttribute('transform', `translate(${offset.x}, ${offset.y})`);
51
54
 
52
- this.outline = DOMUtilities.SVG('rect', 'outline');
55
+ this.outline = DOM.SVG('rect', 'outline');
53
56
 
54
57
  if (primary) {
55
58
 
@@ -58,8 +61,8 @@ export class SVGSelectionBlock {
58
61
  // primary selections have a separate fill, plus the nub. separate
59
62
  // fill because the "target" is unfilled.
60
63
 
61
- this.fill = DOMUtilities.SVG('path', 'fill');
62
- this.nub = DOMUtilities.SVG('rect', 'nub');
64
+ this.fill = DOM.SVG('path', 'fill');
65
+ this.nub = DOM.SVG('rect', 'nub');
63
66
 
64
67
  this.g.appendChild(this.fill);
65
68
  this.g.appendChild(this.outline);
@@ -75,7 +78,7 @@ export class SVGSelectionBlock {
75
78
  // and use currentColor, but we can't set opacity separately so we
76
79
  // need another node. which is a waste, but ergonomics ftw!
77
80
 
78
- this.fill = DOMUtilities.SVG('rect', 'fill');
81
+ this.fill = DOM.SVG('rect', 'fill');
79
82
 
80
83
  // this.SetThemeColor(0);
81
84
  // if (theme.additional_selection_line_dash_array) {
@@ -91,9 +91,9 @@ export interface ImageAnnotationData {
91
91
  * @privateRemarks
92
92
  * why is this a string?
93
93
  */
94
- scale: string;
94
+ scale?: string;
95
95
 
96
- original_size: ImageSize;
96
+ original_size?: ImageSize;
97
97
 
98
98
  }
99
99
 
@@ -58,7 +58,7 @@ import {
58
58
  MDParser,
59
59
  } from 'treb-parser';
60
60
 
61
- import { Yield, SerializeHTML } from 'treb-utils';
61
+ import { SerializeHTML } from 'treb-utils';
62
62
  import type { ParseResult as ParseResult2 } from 'treb-format';
63
63
  import { NumberFormatCache, LotusDate, ValueParser, type Hints, NumberFormat } from 'treb-format';
64
64
  import { SelectionRenderer } from '../render/selection-renderer';
@@ -111,7 +111,7 @@ import { CommandKey
111
111
 
112
112
  import type { DataModel, SerializedModel } from './data_model';
113
113
 
114
- import { DOMUtilities } from 'treb-base-types';
114
+ import { DOMContext } from 'treb-base-types';
115
115
  import { GridBase } from './grid_base';
116
116
  import type { SetRangeOptions } from './set_range_options';
117
117
  import type { ClipboardCellData } from './clipboard_data';
@@ -360,6 +360,8 @@ export class Grid extends GridBase {
360
360
 
361
361
  private tab_bar?: TabBar;
362
362
 
363
+ private DOM = DOMContext.GetInstance();
364
+
363
365
  // --- constructor -----------------------------------------------------------
364
366
 
365
367
  /**
@@ -369,7 +371,8 @@ export class Grid extends GridBase {
369
371
  options: GridOptions = {},
370
372
  model: DataModel,
371
373
  theme: Theme = DefaultTheme,
372
- initialze_dom = true ) {
374
+ initialze_dom = true,
375
+ DOM: DOMContext ) {
373
376
 
374
377
  super(options, model);
375
378
 
@@ -385,7 +388,8 @@ export class Grid extends GridBase {
385
388
  return;
386
389
  }
387
390
 
388
- this.layout = new GridLayout(this.model, this.view);
391
+ this.DOM = DOM;
392
+ this.layout = new GridLayout(this.model, this.view, DOM);
389
393
 
390
394
  if (options.initial_scale) {
391
395
  if (typeof options.initial_scale === 'string') {
@@ -571,84 +575,83 @@ export class Grid extends GridBase {
571
575
 
572
576
  // FIXME: why is this not in layout? it is layout.
573
577
 
574
- view.node = DOMUtilities.Div();
575
- view.node.dataset.scale = this.layout.scale.toString();
576
- view.node.style.fontSize = `${10 * this.layout.scale}pt`;
577
-
578
- view.content_node = DOMUtilities.Div('annotation-content', view.node);
579
- const move_target = DOMUtilities.Div('annotation-move-target', view.node);
580
- const resize_target = DOMUtilities.Div('annotation-resize-target', view.node);
581
-
582
- if (view.node) {
583
- const node = view.node;
584
-
585
- // support focus
586
- node.setAttribute('tabindex', '-1');
578
+ const node = this.DOM.Div('annotation', undefined, {
579
+ data: { scale: this.layout.scale.toString() },
580
+ style: { fontSize: `${10 * this.layout.scale}pt` },
581
+ attrs: { tabindex: '-1', },
582
+ events: {
587
583
 
588
- node.addEventListener('mousedown', (event) => {
589
-
590
- if (event.button !== 0) {
591
- return;
592
- }
584
+ mousedown: (event) => {
593
585
 
594
- // this.AnnotationMouseDown(annotation, event, move_target, resize_target);
595
- this.layout.AnnotationMouseDown(annotation, node, event, move_target, resize_target).then(event => {
596
- // console.info('resolved', event);
597
- if (event) {
598
- this.grid_events.Publish(event);
586
+ if (event.button !== 0) {
587
+ return;
599
588
  }
589
+
590
+ this.layout.AnnotationMouseDown(annotation, node, event, move_target, resize_target).then(event => {
591
+ // console.info('resolved', event);
592
+ if (event) {
593
+ this.grid_events.Publish(event);
594
+ }
595
+
596
+ if (annotation.data.layout) {
597
+ this.EnsureAddress(annotation.data.layout.br.address, 1);
598
+ }
599
+
600
+ });
601
+ },
600
602
 
601
- if (annotation.data.layout) {
602
- this.EnsureAddress(annotation.data.layout.br.address, 1);
603
+ focusin: () => {
604
+
605
+ for (const element of this.layout.GetFrozenAnnotations(annotation)) {
606
+ element.classList.add('clone-focus');
603
607
  }
608
+
609
+ this.selected_annotation = annotation;
610
+ this.primary_selection.empty = true; // FIXME: not using method? (...)
611
+
612
+ // this is done for the side-effect when we start editing, we
613
+ // capture the sheet of the primary selection. if you switch
614
+ // sheets while editing, the selection won't be set so it persists.
615
+ // we need that to switch back to the correct sheet when an edit ends.
616
+
617
+ this.primary_selection.target = { row: -1, column: -1, sheet_id: this.active_sheet.id };
618
+ this.HideGridSelection();
604
619
 
605
- });
606
- });
607
-
608
- node.addEventListener('focusin', () => {
609
-
610
- // console.info('annotation focusin', annotation);
611
-
612
- for (const element of this.layout.GetFrozenAnnotations(annotation)) {
613
- element.classList.add('clone-focus');
614
- }
615
-
616
- this.selected_annotation = annotation;
617
- this.primary_selection.empty = true; // FIXME: not using method? (...)
620
+ },
618
621
 
619
- // this is done for the side-effect when we start editing, we
620
- // capture the sheet of the primary selection. if you switch
621
- // sheets while editing, the selection won't be set so it persists.
622
- // we need that to switch back to the correct sheet when an edit ends.
622
+ focusout: (event) => {
623
623
 
624
- this.primary_selection.target = { row: -1, column: -1, sheet_id: this.active_sheet.id };
625
- this.HideGridSelection();
626
- });
624
+ // console.info('annotation focusout', annotation);
625
+
626
+ for (const element of this.layout.GetFrozenAnnotations(annotation)) {
627
+ element.classList.remove('clone-focus');
628
+ }
629
+
630
+ if (this.formula_bar && this.formula_bar.IsElement((event as FocusEvent).relatedTarget as HTMLElement)) {
631
+ // console.info('editing...');
632
+ this.primary_selection.empty = true;
633
+ this.RenderSelections();
634
+ this.editing_annotation = annotation;
635
+ this.layout.ShowSelections(true);
636
+ }
637
+ else {
638
+ if (this.selected_annotation === annotation) {
639
+ this.selected_annotation = undefined;
640
+ }
641
+ this.ShowGridSelection();
642
+ }
643
+ },
627
644
 
628
- node.addEventListener('focusout', (event) => {
645
+ }
646
+ });
629
647
 
630
- // console.info('annotation focusout', annotation);
648
+ view.node = node;
631
649
 
632
- for (const element of this.layout.GetFrozenAnnotations(annotation)) {
633
- element.classList.remove('clone-focus');
634
- }
635
-
636
- if (this.formula_bar && this.formula_bar.IsElement((event as FocusEvent).relatedTarget as HTMLElement)) {
637
- // console.info('editing...');
638
- this.primary_selection.empty = true;
639
- this.RenderSelections();
640
- this.editing_annotation = annotation;
641
- this.layout.ShowSelections(true);
642
- }
643
- else {
644
- if (this.selected_annotation === annotation) {
645
- this.selected_annotation = undefined;
646
- }
647
- this.ShowGridSelection();
648
- }
649
- });
650
+ view.content_node = this.DOM.Div('annotation-content', node);
651
+ const move_target = this.DOM.Div('annotation-move-target', node);
652
+ const resize_target = this.DOM.Div('annotation-resize-target', node);
650
653
 
651
- node.addEventListener('keydown', (event) => {
654
+ node.addEventListener('keydown', (event) => {
652
655
 
653
656
  const rect = annotation.scaled_rect;
654
657
  if (!rect) {
@@ -748,14 +751,8 @@ export class Grid extends GridBase {
748
751
  }
749
752
 
750
753
  });
751
- }
752
- }
753
754
 
754
- view.node.classList.add('annotation');
755
-
756
- // if (annotation.class_name) {
757
- // annotation.node.classList.add(annotation.class_name);
758
- // }
755
+ }
759
756
 
760
757
  if (add_to_layout) {
761
758
  this.layout.AddAnnotation(annotation);
@@ -2413,7 +2410,7 @@ export class Grid extends GridBase {
2413
2410
  */
2414
2411
  private ActivateSheetTasks() {
2415
2412
 
2416
- this.active_sheet.Activate();
2413
+ this.active_sheet.Activate(this.DOM);
2417
2414
 
2418
2415
  if (this.active_sheet.image && !this.active_sheet.image.complete) {
2419
2416
 
@@ -2785,7 +2782,7 @@ export class Grid extends GridBase {
2785
2782
 
2786
2783
  if (!this.render_token) {
2787
2784
  this.render_token = 1;
2788
- Yield().then(() => {
2785
+ Promise.resolve().then(() => {
2789
2786
  this.render_token = 0;
2790
2787
  this.Repaint(force, full_tile);
2791
2788
  });
@@ -3846,7 +3843,7 @@ export class Grid extends GridBase {
3846
3843
  if (cell.hyperlink) {
3847
3844
  if (this.PointInTextPart(address, offset_point, cell)) {
3848
3845
  const link = cell.hyperlink;
3849
- Yield().then(() => {
3846
+ Promise.resolve().then(() => {
3850
3847
  this.grid_events.Publish({
3851
3848
  type: 'cell-event',
3852
3849
  data: {
@@ -4678,7 +4675,9 @@ export class Grid extends GridBase {
4678
4675
  // console.info('ek', event.key);
4679
4676
 
4680
4677
  if (!selection.empty) {
4681
- this.OverlayEditCell(selection, true, event);
4678
+ if (event.key !== 'Escape') {
4679
+ this.OverlayEditCell(selection, true, event);
4680
+ }
4682
4681
  }
4683
4682
 
4684
4683
  return;