@trebco/treb 29.3.4 → 29.5.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/dist/treb-spreadsheet-light.mjs +12 -12
  2. package/dist/treb-spreadsheet.mjs +12 -12
  3. package/dist/treb.d.ts +36 -41
  4. package/package.json +1 -1
  5. package/treb-base-types/src/area.ts +7 -0
  6. package/treb-base-types/src/cell.ts +2 -46
  7. package/treb-base-types/src/cells.ts +14 -8
  8. package/treb-base-types/src/gradient.ts +2 -2
  9. package/treb-base-types/src/import.ts +2 -2
  10. package/treb-base-types/src/style.ts +79 -6
  11. package/treb-base-types/src/theme.ts +24 -15
  12. package/treb-calculator/src/calculator.ts +22 -12
  13. package/treb-calculator/src/dag/graph.ts +12 -3
  14. package/treb-calculator/src/expression-calculator.ts +66 -74
  15. package/treb-calculator/src/functions/base-functions.ts +2 -2
  16. package/treb-calculator/src/functions/sparkline.ts +2 -2
  17. package/treb-calculator/src/functions/statistics-functions.ts +31 -1
  18. package/treb-data-model/src/data-validation.ts +44 -0
  19. package/treb-data-model/src/data_model.ts +11 -7
  20. package/treb-data-model/src/index.ts +1 -1
  21. package/treb-data-model/src/named.ts +35 -10
  22. package/treb-data-model/src/sheet.ts +75 -15
  23. package/treb-data-model/src/sheet_types.ts +4 -0
  24. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +7 -3
  25. package/treb-embed/src/embedded-spreadsheet.ts +50 -28
  26. package/treb-embed/src/progress-dialog.ts +4 -1
  27. package/treb-embed/src/types.ts +9 -0
  28. package/treb-export/src/drawing2/chart2.ts +20 -38
  29. package/treb-export/src/drawing2/drawing2.ts +2 -107
  30. package/treb-export/src/export-worker/export-worker.ts +1 -1
  31. package/treb-export/src/{export2.ts → export.ts} +439 -628
  32. package/treb-export/src/import2.ts +63 -26
  33. package/treb-export/src/workbook-style2.ts +16 -14
  34. package/treb-export/src/workbook2.ts +2 -18
  35. package/treb-export/src/xml-utils.ts +50 -2
  36. package/treb-export/src/zip-wrapper.ts +1 -1
  37. package/treb-grid/src/editors/overlay_editor.ts +3 -3
  38. package/treb-grid/src/layout/base_layout.ts +5 -14
  39. package/treb-grid/src/render/tile_renderer.ts +49 -48
  40. package/treb-grid/src/types/grid.ts +164 -26
  41. package/treb-grid/src/types/grid_base.ts +93 -17
  42. package/treb-grid/src/types/grid_command.ts +2 -1
  43. package/treb-parser/src/parser-types.ts +10 -0
  44. package/treb-parser/src/parser.ts +55 -17
package/dist/treb.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /*! API v29.3. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
1
+ /*! API v29.5. 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
@@ -743,13 +743,13 @@ export declare class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
743
743
  /**
744
744
  * set or clear cell valiation.
745
745
  *
746
- * @param address - target cell
746
+ * @param target - target cell/area
747
747
  * @param validation - a spreadsheet range, list of data, or undefined. pass
748
748
  * undefined to remove existing cell validation.
749
749
  * @param error - setting an invalid value in the target cell is an error (and
750
750
  * is blocked). defaults to false.
751
751
  */
752
- SetValidation(address: AddressReference, validation?: RangeReference | CellValue[], error?: boolean): void;
752
+ SetValidation(target: RangeReference, validation?: RangeReference | CellValue[], error?: boolean): void;
753
753
 
754
754
  /**
755
755
  * Delete a macro function.
@@ -1042,14 +1042,22 @@ export interface GetRangeOptions {
1042
1042
  formula?: boolean;
1043
1043
 
1044
1044
  /**
1045
- * optional style for returned values (replaces old flags).
1045
+ * by default, GetRange returns cell values. the optional type field
1046
+ * can be used to returns data in different formats.
1046
1047
  *
1047
1048
  * @remarks
1048
1049
  *
1049
1050
  * `formatted` returns formatted values, applying number formatting and
1050
- * returning strings. `formula` returns cell formulas instead of values.
1051
+ * returning strings.
1052
+ *
1053
+ * `A1` returns cell formulas instead of values, in A1 format.
1054
+ *
1055
+ * `R1C1` returns cell formauls in R1C1 format.
1056
+ *
1057
+ * `formula` is an alias for 'A1', for backwards compatibility.
1058
+ *
1051
1059
  */
1052
- type?: 'formatted' | 'formula';
1060
+ type?: 'formatted' | 'A1' | 'R1C1' | 'formula';
1053
1061
  }
1054
1062
 
1055
1063
  /**
@@ -1244,6 +1252,7 @@ export type HorizontalAlign = '' | 'left' | 'center' | 'right';
1244
1252
 
1245
1253
  /** vertical align constants for cell style */
1246
1254
  export type VerticalAlign = '' | 'top' | 'bottom' | 'middle';
1255
+ export type ThemeColorType = typeof ThemeColorList[number];
1247
1256
 
1248
1257
  /**
1249
1258
  * font size for cell style. we generally prefer relative sizes
@@ -1254,20 +1263,20 @@ export interface FontSize {
1254
1263
  unit: 'pt' | 'px' | 'em' | '%';
1255
1264
  value: number;
1256
1265
  }
1257
-
1258
- /**
1259
- * color for cell style. color is used for foreground, background and
1260
- * borders in the cell style. can be either a theme color (theme index
1261
- * plus tint), or CSS text.
1262
- */
1263
- export interface Color {
1264
- theme?: number;
1266
+ export interface HTMLColor {
1267
+ text: string;
1268
+ }
1269
+ export interface ThemeColor {
1270
+ theme: number | ThemeColorType;
1265
1271
  tint?: number;
1266
- text?: string;
1267
-
1268
- /** @deprecated */
1269
- none?: boolean;
1270
1272
  }
1273
+ export interface NullColor {
1274
+ }
1275
+ export type Color = ThemeColor | HTMLColor | NullColor;
1276
+ export declare const ThemeColorIndex: (color: ThemeColor) => number;
1277
+ export declare const IsHTMLColor: (color?: Color) => color is HTMLColor;
1278
+ export declare const IsThemeColor: (color?: Color) => color is ThemeColor;
1279
+ export declare const IsDefinedColor: (color?: Color) => color is ThemeColor | HTMLColor;
1271
1280
  export type CellValue = undefined | string | number | boolean | Complex | DimensionedQuantity;
1272
1281
 
1273
1282
  /**
@@ -1501,7 +1510,7 @@ export declare type LoadSource = "drag-and-drop" | "local-file" | "network-file"
1501
1510
  * EmbeddedSheetEvent is a discriminated union. Switch on the `type` field
1502
1511
  * of the event.
1503
1512
  */
1504
- export type EmbeddedSheetEvent = DocumentChangeEvent | DocumentResetEvent | DocumentLoadEvent | ViewChangeEvent | DataChangeEvent | FocusViewEvent | SelectionEvent | ResizeEvent;
1513
+ export type EmbeddedSheetEvent = DocumentChangeEvent | DocumentResetEvent | DocumentLoadEvent | ThemeChangeEvent | ViewChangeEvent | DataChangeEvent | FocusViewEvent | SelectionEvent | ResizeEvent;
1505
1514
 
1506
1515
  /**
1507
1516
  * options when inserting a table into a sheet
@@ -1540,6 +1549,14 @@ export interface ViewChangeEvent {
1540
1549
  type: 'view-change';
1541
1550
  }
1542
1551
 
1552
+ /**
1553
+ * this event is sent when the theme is updated. it's intended for any
1554
+ * subscribers to update corresponding colors or fonts.
1555
+ */
1556
+ export interface ThemeChangeEvent {
1557
+ type: 'theme-change';
1558
+ }
1559
+
1543
1560
  /**
1544
1561
  * This event is sent when a document is loaded, and also on undo. The
1545
1562
  * source field can help determine if it was triggered by an undo operation.
@@ -1727,7 +1744,6 @@ export interface BaseCellData {
1727
1744
  table?: Table;
1728
1745
  area?: IArea;
1729
1746
  merge_area?: IArea;
1730
- validation?: DataValidation;
1731
1747
  calculated_type?: SerializedValueType;
1732
1748
  note?: string;
1733
1749
  hyperlink?: string;
@@ -1817,27 +1833,6 @@ export interface Table {
1817
1833
  */
1818
1834
  sort?: TableSortOptions;
1819
1835
  }
1820
- export type DataValidation = DataValidationList | DataValidationRange | DataValidationNumber | DataValidationDate | DataValidationBoolean;
1821
- export interface DataValidationBase {
1822
- error?: boolean;
1823
- }
1824
- export interface DataValidationRange extends DataValidationBase {
1825
- type: 'range';
1826
- area: IArea;
1827
- }
1828
- export interface DataValidationList extends DataValidationBase {
1829
- type: 'list';
1830
- list: CellValue[];
1831
- }
1832
- export interface DataValidationDate extends DataValidationBase {
1833
- type: 'date';
1834
- }
1835
- export interface DataValidationNumber extends DataValidationBase {
1836
- type: 'number';
1837
- }
1838
- export interface DataValidationBoolean extends DataValidationBase {
1839
- type: 'boolean';
1840
- }
1841
1836
 
1842
1837
  /**
1843
1838
  * string types for import/export
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trebco/treb",
3
- "version": "29.3.4",
3
+ "version": "29.5.0",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "homepage": "https://treb.app",
6
6
  "repository": {
@@ -584,6 +584,13 @@ export class Area implements IArea {
584
584
  && area.end_.column === this.end_.column;
585
585
  }
586
586
 
587
+ public Equals2(area: IArea): boolean {
588
+ return area.start.row === this.start_.row
589
+ && area.start.column === this.start_.column
590
+ && area.end.row === this.end_.row
591
+ && area.end.column === this.end_.column;
592
+ }
593
+
587
594
  public Clone(): Area {
588
595
  return new Area(this.start, this.end); // ensure copies
589
596
  }
@@ -21,7 +21,7 @@
21
21
 
22
22
  // import { Parser } from 'treb-parser';
23
23
 
24
- import type { Area, IArea } from './area';
24
+ import type { Area } from './area';
25
25
  import type { CellStyle } from './style';
26
26
  import type { TextPart } from './text_part';
27
27
  import type { Complex } from './value-type';
@@ -117,50 +117,6 @@ export type ClickFunction = (options: ClickFunctionOptions) => ClickFunctionResu
117
117
  * - raw per-cell style information. this is in a separate array (object).
118
118
  */
119
119
 
120
- /**
121
- * validation TODO: date, number, boolean, &c
122
- */
123
- export enum ValidationType {
124
- List = 'list',
125
- Date = 'date',
126
- Range = 'range',
127
- Number = 'number',
128
- Boolean = 'boolean',
129
- }
130
-
131
- export interface DataValidationBase {
132
- error?: boolean;
133
- }
134
-
135
- export interface DataValidationRange extends DataValidationBase {
136
- type: 'range'; // ValidationType.Range;
137
- area: IArea;
138
- }
139
-
140
- export interface DataValidationList extends DataValidationBase {
141
- type: 'list'; // ValidationType.List;
142
- list: CellValue[];
143
- }
144
-
145
- export interface DataValidationDate extends DataValidationBase {
146
- type: 'date'; // ValidationType.Date;
147
- }
148
-
149
- export interface DataValidationNumber extends DataValidationBase {
150
- type: 'number'; // ValidationType.Number;
151
- }
152
-
153
- export interface DataValidationBoolean extends DataValidationBase {
154
- type: 'boolean'; // ValidationType.Boolean;
155
- }
156
-
157
- export type DataValidation
158
- = DataValidationList
159
- | DataValidationRange
160
- | DataValidationNumber
161
- | DataValidationDate
162
- | DataValidationBoolean;
163
-
164
120
  export class Cell {
165
121
 
166
122
  // --- static methods -------------------------------------------------------
@@ -342,7 +298,7 @@ export class Cell {
342
298
  /** not editable */
343
299
  // public locked?: boolean;
344
300
 
345
- public validation?: DataValidation;
301
+ // public validation?: DataValidation;
346
302
 
347
303
  // --- class methods --------------------------------------------------------
348
304
 
@@ -26,7 +26,9 @@
26
26
 
27
27
  import type { IArea, ICellAddress} from './area';
28
28
  import { Area, IsCellAddress } from './area';
29
- import type { DataValidation } from './cell';
29
+
30
+ // import type { DataValidation } from './cell';
31
+
30
32
  import { Cell } from './cell';
31
33
  import type { Table } from './table';
32
34
  import { type SerializedValueType, ValueType, GetValueType, ValueTypeList } from './value-type';
@@ -79,7 +81,7 @@ export interface BaseCellData {
79
81
  table?: Table;
80
82
  area?: IArea;
81
83
  merge_area?: IArea;
82
- validation?: DataValidation;
84
+ // validation?: DataValidation;
83
85
  calculated_type?: SerializedValueType; // ValueType;
84
86
  note?: string;
85
87
  hyperlink?: string;
@@ -404,7 +406,7 @@ export class Cells {
404
406
 
405
407
 
406
408
 
407
- /**
409
+ /* *
408
410
  * this method is used for importing legacy data validation types. in those
409
411
  * those we used a numeric enum. we're just dropping that altogether (c.f.
410
412
  * ValueType, which we're keeping) so we need to translate for backcompat.
@@ -419,7 +421,8 @@ export class Cells {
419
421
  * Boolean = 'boolean',
420
422
  * }
421
423
  *
422
- */
424
+ * OK, removed
425
+ * /
423
426
  public ImportDataValidation(value: DataValidation): DataValidation|undefined {
424
427
 
425
428
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -435,6 +438,7 @@ export class Cells {
435
438
 
436
439
  return value;
437
440
  }
441
+ */
438
442
 
439
443
  /**
440
444
  * UPDATE: adding optional style refs, for export
@@ -572,6 +576,7 @@ export class Cells {
572
576
  }
573
577
  }
574
578
 
579
+ /*
575
580
  if (obj.validation) {
576
581
 
577
582
  // the old type used a numeric enum. we just dropped that in favor
@@ -581,6 +586,7 @@ export class Cells {
581
586
  cell.validation = this.ImportDataValidation(obj.validation);
582
587
 
583
588
  }
589
+ */
584
590
 
585
591
  }
586
592
 
@@ -678,7 +684,7 @@ export class Cells {
678
684
  (merge_head || cell.type || (cell.calculated_type && options.expand_arrays) ||
679
685
  (cell.calculated_type && options.calculated_value) ||
680
686
  (cell.note) ||
681
- (cell.validation) ||
687
+ // (cell.validation) ||
682
688
  (options.decorated_cells && cell.style &&
683
689
  ( cell.style.fill || cell.style.border_bottom ||
684
690
  cell.style.border_top || cell.style.border_left || cell.style.border_right)))){
@@ -715,9 +721,9 @@ export class Cells {
715
721
  if (cell.merge_area) {
716
722
  obj.merge_area = cell.merge_area.toJSON();
717
723
  }
718
- if (cell.validation) {
719
- obj.validation = cell.validation; // safe?
720
- }
724
+ // if (cell.validation) {
725
+ // obj.validation = cell.validation; // safe?
726
+ // }
721
727
 
722
728
  if (options.cell_style_refs &&
723
729
  options.cell_style_refs[column] &&
@@ -1,7 +1,7 @@
1
1
 
2
2
  import { Measurement } from 'treb-utils';
3
3
  import { type Color } from './style';
4
- import { type Theme, ThemeColor2 } from './theme';
4
+ import { type Theme, ResolveThemeColor } from './theme';
5
5
  import { ColorFunctions } from './color';
6
6
 
7
7
  export interface GradientStop {
@@ -23,7 +23,7 @@ export class Gradient {
23
23
  throw new Error('invalid stop value');
24
24
  }
25
25
 
26
- const rgb = Measurement.MeasureColor(ThemeColor2(theme, stop.color));
26
+ const rgb = Measurement.MeasureColor(ResolveThemeColor(theme, stop.color));
27
27
 
28
28
  let resolved: number[] = [];
29
29
 
@@ -23,9 +23,8 @@ import type { CellStyle } from './style';
23
23
  import type { SerializedValueType } from './value-type';
24
24
  import type { IArea } from './area';
25
25
  import type { AnnotationLayout } from './layout';
26
- import type { DataValidation } from './cell';
27
26
  import type { Table } from './table';
28
- import type { AnnotationType, ConditionalFormat } from 'treb-data-model';
27
+ import type { DataValidation, AnnotationType, ConditionalFormat } from 'treb-data-model';
29
28
 
30
29
  export interface CellParseResult {
31
30
  row: number,
@@ -60,6 +59,7 @@ export interface ImportedSheetData {
60
59
  row_heights: number[];
61
60
  styles: CellStyle[];
62
61
  conditional_formats: ConditionalFormat[];
62
+ data_validations?: DataValidation[];
63
63
 
64
64
  // optional, for backcompat
65
65
  sheet_style?: number;
@@ -27,6 +27,34 @@ export type HorizontalAlign = '' | 'left' | 'center' | 'right';
27
27
  /** vertical align constants for cell style */
28
28
  export type VerticalAlign = '' | 'top' | 'bottom' | 'middle';
29
29
 
30
+ const ThemeColorList = [
31
+ 'Background',
32
+ 'Text',
33
+ 'Background2',
34
+ 'Text2',
35
+ 'Accent',
36
+ 'Accent2',
37
+ 'Accent3',
38
+ 'Accent4',
39
+ 'Accent5',
40
+ 'Accent6',
41
+ ] as const;
42
+
43
+ export type ThemeColorType = typeof ThemeColorList[number];
44
+
45
+ const ThemeColorMap: Record<string, number> = {};
46
+
47
+ for (const [index, entry] of ThemeColorList.entries()) {
48
+ ThemeColorMap[entry] = index;
49
+ }
50
+
51
+ export const ThemeColorIndex = (color: ThemeColor) => {
52
+ if (typeof color.theme === 'number') {
53
+ return color.theme;
54
+ }
55
+ return ThemeColorMap[color.theme] || 0;
56
+ };
57
+
30
58
  /**
31
59
  * font size for cell style. we generally prefer relative sizes
32
60
  * (percent or em) because they are relative to the default theme
@@ -37,26 +65,67 @@ export interface FontSize {
37
65
  value: number;
38
66
  }
39
67
 
40
- /**
68
+ /* *
41
69
  * color for cell style. color is used for foreground, background and
42
70
  * borders in the cell style. can be either a theme color (theme index
43
71
  * plus tint), or CSS text.
44
72
  *
45
73
  * @privateRemarks
46
74
  * FIXME: this should be a union type. we do a lot of if switching anyway.
47
- */
75
+ * /
48
76
  export interface Color {
49
77
 
50
78
  theme?: number;
51
79
  tint?: number;
52
80
  text?: string;
53
81
 
54
- /** @internal */
82
+ / ** @internal * /
55
83
  offset?: Color;
56
84
 
57
- /** @deprecated */
85
+ / ** @deprecated * /
58
86
  none?: boolean;
59
87
  }
88
+ */
89
+
90
+ export interface HTMLColor {
91
+ text: string;
92
+
93
+ /** @internal */
94
+ offset?: Color;
95
+
96
+ }
97
+
98
+ export interface ThemeColor {
99
+ theme: number|ThemeColorType;
100
+ tint?: number;
101
+
102
+ /** @internal */
103
+ offset?: Color;
104
+
105
+ }
106
+
107
+ export interface NullColor {
108
+
109
+ /** @internal */
110
+ offset?: Color;
111
+
112
+ }
113
+
114
+ export type Color = ThemeColor|HTMLColor|NullColor;
115
+
116
+ export const IsHTMLColor = (color?: Color): color is HTMLColor => {
117
+ return !!color && (typeof (color as HTMLColor).text === 'string');
118
+ };
119
+
120
+ export const IsThemeColor = (color?: Color): color is ThemeColor => {
121
+ return !!color && (typeof (color as ThemeColor).theme !== 'undefined');
122
+ };
123
+
124
+ export const IsDefinedColor = (color?: Color): color is (ThemeColor|HTMLColor) => {
125
+ return !!color && (
126
+ (typeof (color as HTMLColor).text === 'string') ||
127
+ (typeof (color as ThemeColor).theme !== 'undefined'));
128
+ }
60
129
 
61
130
  /** @internal */
62
131
  export interface CompositeBorderEdge {
@@ -258,15 +327,19 @@ export const Style = {
258
327
  return JSON.stringify(style) === empty_json;
259
328
  },
260
329
 
261
- /**
330
+ /* *
262
331
  * this looks like a type guard, we should switch to a union
263
332
  * type and then add real type guards
264
333
  *
265
334
  * @internal
266
- */
335
+ * /
267
336
  ValidColor: (color?: Color): boolean => {
268
337
  return !!(color && (!color.none) && (color.text || color.theme || color.theme === 0));
269
338
  },
339
+ */
340
+
341
+
342
+
270
343
 
271
344
  /** @internal */
272
345
  ParseFontSize: (text = '', default_unit = 'em'): CellStyle => {
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import type { Color, CellStyle } from './style';
22
+ import { type Color, type CellStyle, IsHTMLColor, IsThemeColor, ThemeColorIndex, type ThemeColor } from './style';
23
23
  import { ColorFunctions } from './color';
24
24
  import { DOMContext } from './dom-utilities';
25
25
 
@@ -161,14 +161,20 @@ export const DefaultTheme: Theme = {
161
161
  offset_dark: '#000',
162
162
  };
163
163
 
164
- /**
164
+ /* *
165
165
  * now just a wrapper, we should remove
166
+ *
167
+ * the only difference between this and the other function (ThemeColor2)
168
+ * is that this has a default for "defaultindex" => 0; calls can just
169
+ * call the second method with the extra argument.
170
+ *
166
171
  * @deprecated
167
172
  * @internal
168
- */
173
+ * /
169
174
  export const ThemeColor = (theme: Theme, color?: Color): string => {
170
175
  return ThemeColor2(theme, color, 0);
171
176
  };
177
+ */
172
178
 
173
179
  /**
174
180
  * we cache values in the theme object so that we can dump it when we
@@ -180,7 +186,10 @@ export const ThemeColor = (theme: Theme, color?: Color): string => {
180
186
  *
181
187
  * because this is ephemeral it won't impact export.
182
188
  */
183
- const TintedColor = (theme: Theme, index: number, tint: number) => {
189
+ const TintedColor = (theme: Theme, source: ThemeColor) => {
190
+
191
+ const index = ThemeColorIndex(source);
192
+ let tint = (source.tint || 0);
184
193
 
185
194
  if (theme.mode === 'dark') {
186
195
  tint = -tint; // invert;
@@ -223,9 +232,9 @@ const TintedColor = (theme: Theme, index: number, tint: number) => {
223
232
  *
224
233
  * @internal
225
234
  */
226
- export const ThemeColor2 = (theme: Theme, color?: Color, default_index?: number): string => {
235
+ export const ResolveThemeColor = (theme: Theme, color?: Color, default_index?: number): string => {
227
236
 
228
- if (color?.offset) {
237
+ if (color && color.offset) {
229
238
 
230
239
  // don't do this
231
240
  if (color.offset.offset) {
@@ -233,7 +242,7 @@ export const ThemeColor2 = (theme: Theme, color?: Color, default_index?: number)
233
242
  return '';
234
243
  }
235
244
 
236
- const resolved = ThemeColor2(theme, color.offset);
245
+ const resolved = ResolveThemeColor(theme, color.offset);
237
246
 
238
247
  // check cache
239
248
  if (theme.offset_cache && theme.offset_cache[resolved]) {
@@ -271,17 +280,17 @@ export const ThemeColor2 = (theme: Theme, color?: Color, default_index?: number)
271
280
 
272
281
  // explicit color, or none
273
282
 
274
- if (color?.text) {
283
+ if (IsHTMLColor(color)) {
275
284
  return color.text === 'none' ? '' : color.text;
276
285
  }
277
286
 
278
287
  // theme color. we need a way to cache these lookups, especially for tinting
279
288
 
280
- if (color?.theme || color?.theme === 0) {
289
+ if (IsThemeColor(color)) {
281
290
  if (color.tint) {
282
- return TintedColor(theme, color.theme, color.tint);
291
+ return TintedColor(theme, color);
283
292
  }
284
- return theme.theme_colors ? theme.theme_colors[color.theme] : '';
293
+ return theme.theme_colors ? theme.theme_colors[ThemeColorIndex(color)] : '';
285
294
  }
286
295
 
287
296
  // default from argument
@@ -427,11 +436,11 @@ const DeriveColorScheme = (theme: Theme, context: CanvasRenderingContext2D): 'li
427
436
 
428
437
  // because these are rendered to a canvas, we know that A is 255
429
438
 
430
- context.fillStyle = foreground_color?.text || '';
439
+ context.fillStyle = IsHTMLColor(foreground_color) ? foreground_color.text : '';
431
440
  context.fillRect(0, 0, 3, 3);
432
441
  const fg = ColorFunctions.RGBToHSL(...(Array.from(context.getImageData(1, 1, 1, 1).data) as [number, number, number]));
433
442
 
434
- context.fillStyle = background_color?.text || '';
443
+ context.fillStyle = IsHTMLColor(background_color) ? background_color.text : '';
435
444
  context.fillRect(0, 0, 3, 3);
436
445
  const bg = ColorFunctions.RGBToHSL(...(Array.from(context.getImageData(1, 1, 1, 1).data) as [number, number, number]));
437
446
 
@@ -558,8 +567,8 @@ export const LoadThemeProperties = (container: HTMLElement): Theme => {
558
567
  const compare = css.color;
559
568
 
560
569
  theme.theme_colors = [
561
- theme.grid_cell.fill?.text || 'rgb(255, 255, 255)',
562
- theme.grid_cell.text?.text || 'rgb(51, 51, 51)',
570
+ IsHTMLColor(theme.grid_cell.fill) ? theme.grid_cell.fill.text : 'rgb(255, 255, 255)',
571
+ IsHTMLColor(theme.grid_cell.text) ? theme.grid_cell.text.text : 'rgb(51, 51, 51)',
563
572
  ];
564
573
 
565
574
  for (let i = 1; i < 32; i++) {