@trebco/treb 28.13.2 → 28.15.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.
@@ -29,9 +29,11 @@ import { DOMContext } from 'treb-base-types';
29
29
 
30
30
  // --- from formula_bar ---
31
31
 
32
+ /*
32
33
  export interface FormulaBarResizeEvent {
33
34
  type: 'formula-bar-resize';
34
35
  }
36
+ */
35
37
 
36
38
  export interface FormulaButtonEvent {
37
39
  type: 'formula-button';
@@ -46,7 +48,7 @@ export interface AddressLabelEvent {
46
48
 
47
49
  export type FormulaBar2Event
48
50
  = FormulaButtonEvent
49
- | FormulaBarResizeEvent
51
+ // | FormulaBarResizeEvent
50
52
  | AddressLabelEvent
51
53
  ;
52
54
 
@@ -172,6 +174,7 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
172
174
 
173
175
  this.InitAddressLabel();
174
176
 
177
+ /*
175
178
  if (this.options.insert_function_button) {
176
179
  this.button = DOM.Create('button', 'formula-button', inner_node);
177
180
  this.button.addEventListener('click', () => {
@@ -179,6 +182,7 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
179
182
  this.Publish({ type: 'formula-button', formula });
180
183
  });
181
184
  }
185
+ */
182
186
 
183
187
  this.container_node = container.querySelector('.treb-editor-container') as HTMLDivElement;
184
188
  const target = this.container_node.firstElementChild as HTMLDivElement;
@@ -270,9 +274,18 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
270
274
  this.RegisterListener(descriptor, 'keydown', this.FormulaKeyDown.bind(this));
271
275
  this.RegisterListener(descriptor, 'keyup', this.FormulaKeyUp.bind(this));
272
276
 
277
+ // why is this here, instead of in markup? just an oversight?
278
+
273
279
  if (this.options.expand_formula_button) {
280
+
281
+ let focus_related_target: HTMLElement|undefined;
282
+
274
283
  this.expand_button = DOM.Create('button', 'expand-button', inner_node, {
275
284
  events: {
285
+ focus: (event: FocusEvent) => {
286
+ focus_related_target = event.relatedTarget instanceof HTMLElement ? event.relatedTarget : undefined;
287
+ },
288
+
276
289
  click: (event: MouseEvent) => {
277
290
  event.stopPropagation();
278
291
  event.preventDefault();
@@ -285,6 +298,11 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
285
298
  else {
286
299
  inner_node.setAttribute('expanded', '');
287
300
  }
301
+
302
+ if (focus_related_target) {
303
+ focus_related_target.focus();
304
+ }
305
+
288
306
  },
289
307
  },
290
308
  });
@@ -297,6 +315,10 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
297
315
  return element === this.active_editor?.node;
298
316
  }
299
317
 
318
+ public IsExpandButton(element: HTMLElement): boolean {
319
+ return this.expand_button && (element === this.expand_button);
320
+ }
321
+
300
322
  public InitAddressLabel() {
301
323
 
302
324
  this.address_label.contentEditable = 'true';
@@ -34,6 +34,7 @@ import type { BaseLayout, TileRange } from '../layout/base_layout';
34
34
  import type { DataModel, ViewModel } from '../types/data_model';
35
35
  import type { GridOptions } from '../types/grid_options';
36
36
 
37
+ const DEFAULT_INDENT = ' '; // two spaces in the current font
37
38
  const BASELINE = 'bottom';
38
39
  const WK = /webkit/i.test(typeof navigator === 'undefined' ? '' : navigator?.userAgent || '') ? 1 : 0;
39
40
 
@@ -723,6 +724,15 @@ export class TileRenderer {
723
724
  let override_formatting: string | undefined;
724
725
  let formatted = cell.editing ? '' : cell.formatted; // <-- empty on editing, to remove overflows
725
726
 
727
+ // precalculate indent as string so we can use layout
728
+
729
+ let indent = '';
730
+ if (style.indent) {
731
+ for (let i = 0; i < style.indent; i++) {
732
+ indent += DEFAULT_INDENT;
733
+ }
734
+ }
735
+
726
736
  if (Array.isArray(formatted)) {
727
737
 
728
738
  // type 1 is a multi-part formatted string; used for number formats.
@@ -733,6 +743,15 @@ export class TileRenderer {
733
743
 
734
744
  // this is a single line, with number formatting
735
745
 
746
+ if (indent) {
747
+ if (style.horizontal_align === 'left') {
748
+ formatted.unshift({ text: indent });
749
+ }
750
+ else if (style.horizontal_align === 'right') {
751
+ formatted.push({ text: indent });
752
+ }
753
+ }
754
+
736
755
  for (const part of formatted) {
737
756
  if (part.flag === TextPartFlag.formatting) {
738
757
  override_formatting = part.text;
@@ -810,11 +829,14 @@ export class TileRenderer {
810
829
 
811
830
  // for wrapping
812
831
 
813
- const bound = cell_width - (2 * this.cell_edge_buffer);
832
+ let bound = cell_width - (2 * this.cell_edge_buffer);
814
833
  const strings: RenderTextPart[][] = [];
815
834
 
816
835
  if (style.wrap) {
817
836
 
837
+ const indent_width = (indent && style.horizontal_align !== 'center') ? context.measureText(indent).width : 0;
838
+ bound -= indent_width;
839
+
818
840
  for (const line of md) {
819
841
 
820
842
  // we should probably normalize whitespace -- because formatting
@@ -921,14 +943,25 @@ export class TileRenderer {
921
943
 
922
944
  max_width = Math.max(max_width, last.width);
923
945
 
924
- strings.push(line2.map((metric) => {
946
+ const line_string = line2.map((metric) => {
925
947
  return {
926
948
  ...metric.part,
927
949
  hidden: false,
928
950
  width: metric.width,
929
951
  text: metric.text,
930
952
  };
931
- }));
953
+ });
954
+
955
+ if (style.indent) {
956
+ if (style.horizontal_align === 'left') {
957
+ line_string.unshift({ text: indent, hidden: false, width: indent_width });
958
+ }
959
+ else if (style.horizontal_align === 'right') {
960
+ line_string.push({ text: indent, hidden: false, width: indent_width });
961
+ }
962
+ }
963
+
964
+ strings.push(line_string);
932
965
 
933
966
  }
934
967
 
@@ -939,9 +972,19 @@ export class TileRenderer {
939
972
 
940
973
  // simple case
941
974
 
975
+
942
976
  for (const line of md) {
943
977
  const parts: RenderTextPart[] = [];
944
978
 
979
+ if (style.indent) {
980
+ if (style.horizontal_align === 'left') {
981
+ line.unshift({ text: indent });
982
+ }
983
+ else if (style.horizontal_align === 'right') {
984
+ line.push({ text: indent });
985
+ }
986
+ }
987
+
945
988
  let line_width = 0;
946
989
 
947
990
  for (const element of line) {
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import type { ICellAddress, AnnotationLayout, IRectangle } from 'treb-base-types';
22
+ import type { ICellAddress, AnnotationLayout, IRectangle, CellStyle } from 'treb-base-types';
23
23
  import { Rectangle } from 'treb-base-types';
24
24
 
25
25
  /**
@@ -97,7 +97,7 @@ export interface ImageAnnotationData {
97
97
 
98
98
  }
99
99
 
100
- export type AnnotationType = 'treb-chart'|'image'|'external';
100
+ export type AnnotationType = 'treb-chart'|'image'|'textbox'|'external';
101
101
 
102
102
  /**
103
103
  * splitting persisted data from the annotation class. that class might
@@ -182,12 +182,26 @@ export interface AnnotationChartData extends AnnotationDataBase {
182
182
  type: 'treb-chart';
183
183
  }
184
184
 
185
+ export interface AnnotationTextBoxData extends AnnotationDataBase {
186
+ type: 'textbox';
187
+ data: {
188
+ style?: CellStyle;
189
+ paragraphs: {
190
+ style?: CellStyle,
191
+ content: {
192
+ text: string,
193
+ style?: CellStyle
194
+ }[],
195
+ }[];
196
+ };
197
+ };
198
+
185
199
  export interface AnnotationExternalData extends AnnotationDataBase {
186
200
  type: 'external';
187
201
  data: Record<string, string>;
188
202
  }
189
203
 
190
- export type AnnotationData = AnnotationChartData | AnnotationImageData | AnnotationExternalData;
204
+ export type AnnotationData = AnnotationChartData | AnnotationImageData | AnnotationExternalData | AnnotationTextBoxData;
191
205
 
192
206
  /**
193
207
  * why is this a class? it doesn't do anything.
@@ -634,6 +634,14 @@ export class Grid extends GridBase {
634
634
  this.editing_annotation = annotation;
635
635
  this.layout.ShowSelections(true);
636
636
  }
637
+ else if (this.formula_bar?.IsExpandButton(event.relatedTarget as HTMLElement)) {
638
+
639
+ // for this particular case, do nothing. basically you are
640
+ // expanding/contracting the formula bar. we want to preserve
641
+ // the selected annotation, if any. after the operation we'll
642
+ // restore focus.
643
+
644
+ }
637
645
  else {
638
646
  if (this.selected_annotation === annotation) {
639
647
  this.selected_annotation = undefined;
@@ -68,8 +68,9 @@ export interface GridOptions {
68
68
  /* * show delete tab in the tab bar */
69
69
  // delete_tab?: boolean;
70
70
 
71
- /** show the "insert function" button. requires formula bar. */
71
+ /* * show the "insert function" button. requires formula bar. * /
72
72
  insert_function_button?: boolean;
73
+ */
73
74
 
74
75
  /** button to increase/reduce size of formula editor */
75
76
  expand_formula_button?: boolean;
@@ -97,7 +98,7 @@ export const DefaultGridOptions: GridOptions = {
97
98
  formula_bar: true,
98
99
  add_tab: false,
99
100
  tab_bar: 'auto',
100
- insert_function_button: false,
101
+ // insert_function_button: false,
101
102
  expand_formula_button: false,
102
103
  expand: true,
103
104
  repaint_on_cell_change: true,
@@ -92,10 +92,17 @@ export class NamedRangeCollection {
92
92
  console.warn('invalid name');
93
93
  return false;
94
94
  }
95
+
96
+ // why is this considered invalid here? I've seen it done.
97
+ // maybe something we're doing with these ranges doesn't
98
+ // collapse them? (...)
99
+
95
100
  if (range.entire_column || range.entire_row) {
96
- console.warn('invalid range');
101
+ console.info({range});
102
+ console.warn(`invalid range`);
97
103
  return false;
98
104
  }
105
+
99
106
  this.forward[validated] = range;
100
107
  if (apply) {
101
108
  this.RebuildList();