@trebco/treb 30.9.2 → 30.10.1

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 v30.9. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
1
+ /*! API v30.10. 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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trebco/treb",
3
- "version": "30.9.2",
3
+ "version": "30.10.1",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "homepage": "https://treb.app",
6
6
  "repository": {
@@ -21,6 +21,8 @@
21
21
 
22
22
  import { type Color, type CellStyle, IsHTMLColor, IsThemeColor, ThemeColorIndex, type ThemeColor } from './style';
23
23
  import { ColorFunctions } from './color';
24
+ // import * as LCHColorFunctions from './color2';
25
+
24
26
  import { DOMContext } from './dom-utilities';
25
27
  import { Measurement } from 'treb-utils';
26
28
 
@@ -107,7 +109,7 @@ export interface Theme {
107
109
  theme_colors?: string[];
108
110
 
109
111
  /** as RGB, so we can adjust them */
110
- theme_colors_rgb?: number[][];
112
+ theme_colors_rgb?: [number, number, number][];
111
113
 
112
114
  /**
113
115
  * cache tinted colors. the way this works is we index by the
@@ -207,7 +209,8 @@ const TintedColor = (theme: Theme, source: ThemeColor) => {
207
209
  let color = theme.tint_cache[index][tint];
208
210
  if (!color) {
209
211
 
210
- const rgb = (theme.theme_colors_rgb ? theme.theme_colors_rgb[index] : [0, 0, 0]) || [0, 0, 0];
212
+ const rgb: [number, number, number] = (theme.theme_colors_rgb ? theme.theme_colors_rgb[index] : [0, 0, 0]) || [0, 0, 0];
213
+
211
214
  let tinted: {r: number, g: number, b: number};
212
215
  if (tint > 0) {
213
216
  tinted = ColorFunctions.Lighten(rgb[0], rgb[1], rgb[2], tint * 100, true);
@@ -216,6 +219,21 @@ const TintedColor = (theme: Theme, source: ThemeColor) => {
216
219
  tinted = ColorFunctions.Darken(rgb[0], rgb[1], rgb[2], -tint * 100, true);
217
220
  }
218
221
  color = `rgb(${tinted.r},${tinted.g},${tinted.b})`;
222
+
223
+ /*
224
+ // L is in [0, 100] and the passed tint value is between (-1 and 1). but
225
+ // is the tint value the desired value, or the adjustment? (...)
226
+ // looks like it's the adjustment. makes sense I guess if you pick the
227
+ // original colors.
228
+
229
+ // if the tint value was not originally in perceptual space we might need
230
+ // to curve it a bit? (...)
231
+
232
+ const lch = LCHColorFunctions.RGBToLCH(...rgb);
233
+ const tinted = LCHColorFunctions.LCHToRGB(lch.l + 50 * tint, lch.c, lch.h);
234
+ color = `rgb(${tinted.r},${tinted.g},${tinted.b})`;
235
+ */
236
+
219
237
  theme.tint_cache[index][tint] = color;
220
238
 
221
239
  }
@@ -624,7 +642,7 @@ export const LoadThemeProperties = (container: HTMLElement): Theme => {
624
642
  context.fillStyle = color;
625
643
  context.fillRect(0, 0, 3, 3);
626
644
  const imagedata = context.getImageData(1, 1, 1, 1);
627
- return Array.from(imagedata.data);
645
+ return Array.from(imagedata.data) as [number, number, number];
628
646
  });
629
647
  }
630
648
 
@@ -55,20 +55,64 @@
55
55
  * of times we have to define the same colors.
56
56
  */
57
57
 
58
- // moved // background: var(--treb-chart-background, #fff);
59
-
60
- .series-1 { color: var(--treb-chart-color-series-1, #80B1D3); }
61
- .series-2 { color: var(--treb-chart-color-series-2, #8DD3C7); }
62
- .series-3 { color: var(--treb-chart-color-series-3, #BEBADA); }
63
- .series-4 { color: var(--treb-chart-color-series-4, #FB8072); }
64
- .series-5 { color: var(--treb-chart-color-series-5, #FDB462); }
65
- .series-6 { color: var(--treb-chart-color-series-6, #B3DE69); }
66
- .series-7 { color: var(--treb-chart-color-series-7, #FCCDE5); }
67
- .series-8 { color: var(--treb-chart-color-series-8, #D9D9D9); }
68
- .series-9 { color: var(--treb-chart-color-series-9, #BC80BD); }
69
- .series-10 { color: var(--treb-chart-color-series-10, #CCEBC5); }
70
- .series-11 { color: var(--treb-chart-color-series-11, #FFED6F); }
71
- .series-12 { color: var(--treb-chart-color-series-12, #FFFFB3); }
58
+ // lightness offsets for subsequent colors. is there a way we could
59
+ // have the charts just use a modulo and an offset? (...) would be
60
+ // cleaner maybe
61
+
62
+ /* something like this:
63
+ *
64
+ * .series-1 { color: var(--theme-color); --base-color: var(--theme-color); }
65
+ * .segment-2 { color: lch(from var(--base-color) calc(l + 20) c h); }
66
+ *
67
+ */
68
+
69
+ --segment-2-offset: -20;
70
+ --segment-3-offset: 10;
71
+ --segment-4-offset: -10;
72
+ --segment-5-offset: 20;
73
+ --segment-6-offset: -25;
74
+
75
+ .series-1 { color: var(--treb-applied-theme-color-1); }
76
+ .series-2 { color: var(--treb-applied-theme-color-2); }
77
+ .series-3 { color: var(--treb-applied-theme-color-3); }
78
+ .series-4 { color: var(--treb-applied-theme-color-4); }
79
+ .series-5 { color: var(--treb-applied-theme-color-5); }
80
+ .series-6 { color: var(--treb-applied-theme-color-6); }
81
+
82
+ .series-7 { color: hsl(from var(--treb-applied-theme-color-1) h s calc(l + var(--segment-2-offset))); }
83
+ .series-8 { color: hsl(from var(--treb-applied-theme-color-2) h s calc(l + var(--segment-2-offset))); }
84
+ .series-9 { color: hsl(from var(--treb-applied-theme-color-3) h s calc(l + var(--segment-2-offset))); }
85
+ .series-10 { color: hsl(from var(--treb-applied-theme-color-4) h s calc(l + var(--segment-2-offset))); }
86
+ .series-11 { color: hsl(from var(--treb-applied-theme-color-5) h s calc(l + var(--segment-2-offset))); }
87
+ .series-12 { color: hsl(from var(--treb-applied-theme-color-6) h s calc(l + var(--segment-2-offset))); }
88
+
89
+ .series-13 { color: hsl(from var(--treb-applied-theme-color-1) h s calc(l + var(--segment-3-offset))); }
90
+ .series-14 { color: hsl(from var(--treb-applied-theme-color-2) h s calc(l + var(--segment-3-offset))); }
91
+ .series-15 { color: hsl(from var(--treb-applied-theme-color-3) h s calc(l + var(--segment-3-offset))); }
92
+ .series-16 { color: hsl(from var(--treb-applied-theme-color-4) h s calc(l + var(--segment-3-offset))); }
93
+ .series-17 { color: hsl(from var(--treb-applied-theme-color-5) h s calc(l + var(--segment-3-offset))); }
94
+ .series-18 { color: hsl(from var(--treb-applied-theme-color-6) h s calc(l + var(--segment-3-offset))); }
95
+
96
+ .series-19 { color: hsl(from var(--treb-applied-theme-color-1) h s calc(l + var(--segment-4-offset))); }
97
+ .series-20 { color: hsl(from var(--treb-applied-theme-color-2) h s calc(l + var(--segment-4-offset))); }
98
+ .series-21 { color: hsl(from var(--treb-applied-theme-color-3) h s calc(l + var(--segment-4-offset))); }
99
+ .series-22 { color: hsl(from var(--treb-applied-theme-color-4) h s calc(l + var(--segment-4-offset))); }
100
+ .series-23 { color: hsl(from var(--treb-applied-theme-color-5) h s calc(l + var(--segment-4-offset))); }
101
+ .series-24 { color: hsl(from var(--treb-applied-theme-color-6) h s calc(l + var(--segment-4-offset))); }
102
+
103
+ .series-25 { color: hsl(from var(--treb-applied-theme-color-1) h s calc(l + var(--segment-5-offset))); }
104
+ .series-26 { color: hsl(from var(--treb-applied-theme-color-2) h s calc(l + var(--segment-5-offset))); }
105
+ .series-27 { color: hsl(from var(--treb-applied-theme-color-3) h s calc(l + var(--segment-5-offset))); }
106
+ .series-28 { color: hsl(from var(--treb-applied-theme-color-4) h s calc(l + var(--segment-5-offset))); }
107
+ .series-29 { color: hsl(from var(--treb-applied-theme-color-5) h s calc(l + var(--segment-5-offset))); }
108
+ .series-30 { color: hsl(from var(--treb-applied-theme-color-6) h s calc(l + var(--segment-5-offset))); }
109
+
110
+ .series-31 { color: hsl(from var(--treb-applied-theme-color-1) h s calc(l + var(--segment-6-offset))); }
111
+ .series-32 { color: hsl(from var(--treb-applied-theme-color-2) h s calc(l + var(--segment-6-offset))); }
112
+ .series-33 { color: hsl(from var(--treb-applied-theme-color-3) h s calc(l + var(--segment-6-offset))); }
113
+ .series-34 { color: hsl(from var(--treb-applied-theme-color-4) h s calc(l + var(--segment-6-offset))); }
114
+ .series-35 { color: hsl(from var(--treb-applied-theme-color-5) h s calc(l + var(--segment-6-offset))); }
115
+ .series-36 { color: hsl(from var(--treb-applied-theme-color-6) h s calc(l + var(--segment-6-offset))); }
72
116
 
73
117
  /* chart title, at top or bottom */
74
118
  .chart-title {
@@ -35,7 +35,7 @@ import type { SerializedValueType } from 'treb-base-types';
35
35
  import type { Sheet} from './workbook-sheet2';
36
36
  import { VisibleState } from './workbook-sheet2';
37
37
  import type { CellAnchor } from './drawing2/drawing2';
38
- import { type DOMContent, XMLUtils } from './xml-utils';
38
+ import { type GenericDOMElement, XMLUtils } from './xml-utils';
39
39
 
40
40
  // import { one_hundred_pixels } from './constants';
41
41
  import { ColumnWidthToPixels } from './column-width';
@@ -52,6 +52,55 @@ interface SharedFormula {
52
52
 
53
53
  interface SharedFormulaMap { [index: string]: SharedFormula }
54
54
 
55
+ interface CellElementType {
56
+ a$: {
57
+ r?: string;
58
+ t?: string;
59
+ s?: string;
60
+ };
61
+ v?: string|number|{
62
+ t$: string;
63
+ a$?: Record<string, string>; // DOMContent;
64
+ };
65
+ f?: string|{
66
+ t$: string;
67
+ a$?: {
68
+ si?: string;
69
+ t?: string;
70
+ ref?: string;
71
+ },
72
+ };
73
+ };
74
+
75
+ interface ConditionalFormatRule {
76
+ a$: {
77
+ type?: string;
78
+ dxfId?: string;
79
+ priority?: string;
80
+ operator?: string;
81
+ };
82
+ formula?: string|[number,number]|{t$: string};
83
+ colorScale?: {
84
+ cfvo?: {
85
+ a$: {
86
+ type?: string;
87
+ val?: string;
88
+ }
89
+ }[];
90
+ color?: {
91
+ a$: {
92
+ rgb?: string;
93
+ theme?: string;
94
+ tint?: string;
95
+ }
96
+ }[];
97
+ };
98
+ }
99
+
100
+ const ElementHasTextNode = (test: unknown): test is {t$: string} => {
101
+ return typeof test === 'object' && typeof (test as {$t: string}).$t !== 'undefined';
102
+ }
103
+
55
104
  export class Importer {
56
105
 
57
106
  // FIXME: need a way to share/pass parser flags
@@ -76,25 +125,7 @@ export class Importer {
76
125
 
77
126
  public ParseCell(
78
127
  sheet: Sheet,
79
- element: {
80
- a$: {
81
- r?: string;
82
- t?: string;
83
- s?: string;
84
- };
85
- v?: string|number|{
86
- t$: string;
87
- a$?: DOMContent;
88
- };
89
- f?: string|{
90
- t$: string;
91
- a$?: {
92
- si?: string;
93
- t?: string;
94
- ref?: string;
95
- },
96
- };
97
- },
128
+ element: CellElementType,
98
129
  shared_formulae: SharedFormulaMap,
99
130
  arrays: RangeType[],
100
131
  merges: RangeType[],
@@ -178,7 +209,12 @@ export class Importer {
178
209
  if (/^_xll\./.test(unit.name)) {
179
210
  unit.name = unit.name.substring(5);
180
211
  }
181
- else if (/^_xlfn\./.test(unit.name)) {
212
+ if (/^_xlfn\./.test(unit.name)) {
213
+ console.info("xlfn:", unit.name);
214
+ unit.name = unit.name.substring(6);
215
+ }
216
+ if (/^_xlws\./.test(unit.name)) {
217
+ console.info("xlws:", unit.name);
182
218
  unit.name = unit.name.substring(6);
183
219
  }
184
220
  }
@@ -347,11 +383,13 @@ export class Importer {
347
383
 
348
384
  }
349
385
 
350
- public ParseConditionalFormat(address: RangeType|AddressType, rule: any): ConditionalFormat|ConditionalFormat[]|undefined {
386
+ public ParseConditionalFormat(address: RangeType|AddressType, rule: ConditionalFormatRule): ConditionalFormat|ConditionalFormat[]|undefined {
351
387
 
352
388
  const area = this.AddressToArea(address);
353
389
  const operators = ConditionalFormatOperators;
354
390
 
391
+ // console.info({rule});
392
+
355
393
  switch (rule.a$.type) {
356
394
  case 'duplicateValues':
357
395
  case 'uniqueValues':
@@ -431,7 +469,7 @@ export class Importer {
431
469
  if (rule.formula) {
432
470
 
433
471
  if (typeof rule.formula !== 'string') {
434
- if (rule.formula.t$) {
472
+ if (ElementHasTextNode(rule.formula)) {
435
473
 
436
474
  // the only case (to date) we've seen here is that the attribute
437
475
  // is "xml:space=preserve", which we can ignore (are you sure?)
@@ -442,7 +480,7 @@ export class Importer {
442
480
  }
443
481
  else {
444
482
  console.info("unexpected conditional expression", {rule});
445
-
483
+ rule.formula = '';
446
484
  }
447
485
  }
448
486
 
@@ -520,7 +558,7 @@ export class Importer {
520
558
  else if (color_element.a$.theme) {
521
559
  (color as ThemeColor).theme = Number(color_element.a$.theme) || 0;
522
560
  if (color_element.a$.tint) {
523
- (color as ThemeColor).tint = Math.round(color_element.a$.tint * 1000) / 1000;
561
+ (color as ThemeColor).tint = Math.round(Number(color_element.a$.tint) * 1000) / 1000;
524
562
  }
525
563
  }
526
564
 
@@ -595,7 +633,7 @@ export class Importer {
595
633
 
596
634
  const annotations: AnchoredAnnotation[] = [];
597
635
 
598
- const FindAll: (path: string) => any[] = XMLUtils.FindAll.bind(XMLUtils, sheet.sheet_data);
636
+ const FindAll: <T = GenericDOMElement>(path: string) => T[] = XMLUtils.FindAll.bind(XMLUtils, sheet.sheet_data);
599
637
 
600
638
  // tab color
601
639
 
@@ -640,7 +678,7 @@ export class Importer {
640
678
  if (element.cfRule) {
641
679
  const rules = Array.isArray(element.cfRule) ? element.cfRule : [element.cfRule];
642
680
  for (const rule of rules) {
643
- const format = this.ParseConditionalFormat(area, rule);
681
+ const format = this.ParseConditionalFormat(area, rule as unknown as ConditionalFormatRule);
644
682
  if (format) {
645
683
  if (Array.isArray(format)) {
646
684
  conditional_formats.push(...format);
@@ -661,7 +699,7 @@ export class Importer {
661
699
  const merge_cells = FindAll('worksheet/mergeCells/mergeCell');
662
700
 
663
701
  for (const element of merge_cells) {
664
- if (element.a$.ref) {
702
+ if (element.a$?.ref) {
665
703
  const merge = sheet.TranslateAddress(element.a$.ref);
666
704
  if (is_range(merge)) {
667
705
  merges.push(ShiftRange(merge, -1, -1));
@@ -677,7 +715,7 @@ export class Importer {
677
715
  const ref = entry.a$?.sqref;
678
716
  const formula = entry.formula1;
679
717
 
680
- if (ref && formula && type === 'list') {
718
+ if (ref && formula && typeof formula === 'string' && type === 'list') {
681
719
  // let address: ICellAddress|undefined;
682
720
  let validation: DataValidation|undefined;
683
721
  let parse_result = this.parser.Parse(ref);
@@ -796,8 +834,8 @@ export class Importer {
796
834
 
797
835
  }
798
836
  else {
799
- reference = child.__location || '';
800
- text = child.__display || '';
837
+ reference = typeof child.__location === 'string' ? child.__location : '';
838
+ text = typeof child.__display === 'string' ? child.__display : '';
801
839
  }
802
840
 
803
841
  links.push({ address, reference, text });
@@ -864,11 +902,10 @@ export class Importer {
864
902
  row_heights[row_index - 1] = height;
865
903
  }
866
904
 
867
- let cells = row.c || [];
868
- if (!Array.isArray(cells)) { cells = [cells]; }
905
+ const cells = row.c ? Array.isArray(row.c) ? row.c : [row.c] : [];
869
906
 
870
907
  for (const element of cells) {
871
- const cell = this.ParseCell(sheet, element, shared_formulae, arrays, merges, links); // , validations);
908
+ const cell = this.ParseCell(sheet, element as unknown as CellElementType, shared_formulae, arrays, merges, links); // , validations);
872
909
  if (cell) {
873
910
  data.push(cell);
874
911
  }
@@ -20,10 +20,10 @@
20
20
  */
21
21
 
22
22
  import { XMLParser } from 'fast-xml-parser';
23
- import { XMLUtils, XMLOptions, XMLOptions2 } from './xml-utils';
23
+ import { XMLUtils, XMLOptions2 } from './xml-utils';
24
24
 
25
25
  // const xmlparser = new XMLParser();
26
- const xmlparser1 = new XMLParser(XMLOptions);
26
+ // const xmlparser1 = new XMLParser(XMLOptions);
27
27
  const xmlparser2 = new XMLParser(XMLOptions2);
28
28
 
29
29
  // import * as he from 'he';
@@ -514,7 +514,8 @@ export class Workbook {
514
514
  const data = this.zip.Get(reference.replace(/^../, 'xl'));
515
515
  if (!data) { return undefined; }
516
516
 
517
- const xml = xmlparser1.parse(data);
517
+ // const xml = xmlparser1.parse(data);
518
+ const xml = xmlparser2.parse(data);
518
519
 
519
520
  const result: ChartDescription = {
520
521
  type: ChartType.Unknown
@@ -532,8 +533,8 @@ export class Workbook {
532
533
  if (typeof node === 'string') {
533
534
  result.title = node;
534
535
  }
535
- else if (node.text__) {
536
- result.title = node.text__; // why is this not quoted, if the later one is quoted? is this a reference?
536
+ else if (node.t$) {
537
+ result.title = node.t$; // why is this not quoted, if the later one is quoted? is this a reference?
537
538
  }
538
539
  }
539
540
  else {
@@ -553,14 +554,14 @@ export class Workbook {
553
554
  series_nodes = [series_nodes];
554
555
  }
555
556
 
556
- // console.info("SN", series_nodes);
557
+ // console.info({SN: series_nodes});
557
558
 
558
559
  for (const series_node of series_nodes) {
559
560
 
560
561
  let index = series.length;
561
562
  const order_node = series_node['c:order'];
562
563
  if (order_node) {
563
- index = Number(order_node.__val||0) || 0;
564
+ index = Number(order_node.a$?.val||0) || 0;
564
565
  }
565
566
 
566
567
  const series_data: ChartSeries = {};
@@ -626,7 +627,7 @@ export class Workbook {
626
627
  result.type = ChartType.Bar;
627
628
  // console.info("BD", node);
628
629
  if (node['c:barDir']) {
629
- if (node['c:barDir'].__val === 'col') {
630
+ if (node['c:barDir'].a$?.val === 'col') {
630
631
  result.type = ChartType.Column;
631
632
  }
632
633
  }
@@ -682,7 +683,7 @@ export class Workbook {
682
683
 
683
684
  const ex_series = XMLUtils.FindAll(xml, 'cx:chartSpace/cx:chart/cx:plotArea/cx:plotAreaRegion/cx:series');
684
685
  if (ex_series?.length) {
685
- if (ex_series.every(test => test.__layoutId === 'boxWhisker')) {
686
+ if (ex_series.every(test => test.a$?.layoutId === 'boxWhisker')) {
686
687
  result.type = ChartType.Box;
687
688
  result.series = [];
688
689
  const data = XMLUtils.FindAll(xml, 'cx:chartSpace/cx:chartData/cx:data'); // /cx:data/cx:numDim/cx:f');
@@ -693,9 +694,9 @@ export class Workbook {
693
694
 
694
695
  const series: ChartSeries = {};
695
696
 
696
- const id = Number(entry['cx:dataId']?.['__val']);
697
+ const id = Number(entry['cx:dataId']?.a$?.val);
697
698
  for (const data_series of data) {
698
- if (Number(data_series.__id) === id) {
699
+ if (Number(data_series.a$?.id) === id) {
699
700
  series.values = data_series['cx:numDim']?.['cx:f'] || '';
700
701
  break;
701
702
  }
@@ -28,6 +28,26 @@ export interface DOMContent {
28
28
  [index: string]: string|DOMContent|string[]|DOMContent[]|number|number[]|undefined;
29
29
  }
30
30
 
31
+ // --- take 2 ------------------------------------------------------------------
32
+
33
+ export interface XMLKeys {
34
+ a$?: Record<string, string>;
35
+ t$?: string;
36
+ }
37
+
38
+ export type DOMElementType = number|number[]|string|string[]|(BaseDOM & XMLKeys)|(BaseDOM & XMLKeys)[];
39
+
40
+ export interface BaseDOM {
41
+ [key: string]: DOMElementType;
42
+ }
43
+
44
+ export type GenericDOMElement = BaseDOM & XMLKeys;
45
+
46
+ export const GenericDOMArray = (element: GenericDOMElement|GenericDOMElement[]): GenericDOMElement[] => element ? Array.isArray(element) ? element : [element] : [];
47
+
48
+ // -----------------------------------------------------------------------------
49
+
50
+
31
51
  /**
32
52
  * not sure why we have to do this, but filter attributes that
33
53
  * have value === undefined
@@ -76,6 +96,7 @@ export const PatchXMLBuilder = (options: Partial<XmlBuilderOptions>) => {
76
96
 
77
97
  //////////////////
78
98
 
99
+ /*
79
100
  export const XMLOptions: Partial<X2jOptions> = {
80
101
  ignoreAttributes: false,
81
102
  attributeNamePrefix: '__',
@@ -84,6 +105,7 @@ export const XMLOptions: Partial<X2jOptions> = {
84
105
  tagValueProcessor: XMLTagProcessor,
85
106
  ignoreDeclaration: true,
86
107
  };
108
+ */
87
109
 
88
110
  /**
89
111
  * group attributes under `a$`, and don't add attribute prefixes (should be
@@ -91,7 +113,6 @@ export const XMLOptions: Partial<X2jOptions> = {
91
113
  */
92
114
  export const XMLOptions2: Partial<X2jOptions> = {
93
115
  ignoreAttributes: false,
94
- // attrNodeName: 'a$', // FXP v4
95
116
  attributesGroupName: 'a$',
96
117
  attributeNamePrefix: '',
97
118
  textNodeName: 't$',
@@ -96,6 +96,8 @@ export abstract class BaseLayout {
96
96
 
97
97
  public header_size: Size = { width: 0, height: 0 };
98
98
 
99
+ public applied_theme_colors: string[] = [];
100
+
99
101
  /**
100
102
  * last rendered column. this is used to calculate the limits of
101
103
  * cell overflows, which may exceed actual data in the sheet.
@@ -1280,6 +1282,18 @@ export abstract class BaseLayout {
1280
1282
 
1281
1283
  }
1282
1284
 
1285
+ public ApplyThemeColors() {
1286
+
1287
+ // what's the best node for this? (...)
1288
+
1289
+ if (this.container) {
1290
+ for (const [index, entry] of this.applied_theme_colors.entries()) {
1291
+ this.container.style.setProperty(`--treb-applied-theme-color-${index + 1}`, entry);
1292
+ }
1293
+
1294
+ }
1295
+ }
1296
+
1283
1297
  /**
1284
1298
  * applies theme to nodes, as necessary
1285
1299
  */
@@ -1307,6 +1321,13 @@ export abstract class BaseLayout {
1307
1321
 
1308
1322
  this.dropdown_list.style.font = Style.Font(theme.grid_cell || {});
1309
1323
 
1324
+ // testing
1325
+
1326
+ this.applied_theme_colors = theme.theme_colors?.slice(4, 10) || [];
1327
+ if (this.container) {
1328
+ this.ApplyThemeColors();
1329
+ }
1330
+
1310
1331
  }
1311
1332
 
1312
1333
  public UpdateTotalSize(): void {
@@ -95,6 +95,8 @@ export class GridLayout extends BaseLayout {
95
95
 
96
96
  this.container.addEventListener('scroll', () => scroll_callback());
97
97
 
98
+ this.ApplyThemeColors();
99
+
98
100
  }
99
101
 
100
102
  public ResizeCursor(resize?: 'row'|'column'): void {