@trebco/treb 30.8.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-export-worker.mjs +2 -2
- package/dist/treb-spreadsheet.mjs +9 -9
- package/dist/treb.d.ts +4 -1
- package/package.json +1 -1
- package/treb-base-types/src/color.ts +32 -0
- package/treb-base-types/src/import.ts +3 -4
- package/treb-base-types/src/theme.ts +55 -10
- package/treb-charts/style/charts.scss +58 -14
- package/treb-data-model/src/sheet.ts +11 -1
- package/treb-data-model/src/sheet_types.ts +4 -1
- package/treb-embed/style/theme-defaults.scss +16 -0
- package/treb-export/src/export.ts +40 -7
- package/treb-export/src/{import2.ts → import.ts} +121 -49
- package/treb-export/src/index.worker.ts +1 -1
- package/treb-export/src/workbook2.ts +14 -13
- package/treb-export/src/xml-utils.ts +22 -1
- package/treb-grid/src/layout/base_layout.ts +21 -0
- package/treb-grid/src/layout/grid_layout.ts +2 -0
- package/treb-grid/src/types/grid.ts +9 -5
- package/treb-grid/src/types/tab_bar.ts +38 -1
- package/treb-charts/style/old-charts.scss +0 -250
package/dist/treb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! API v30.
|
|
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
|
|
@@ -1779,6 +1779,9 @@ export interface SerializedSheet {
|
|
|
1779
1779
|
/** sheet name */
|
|
1780
1780
|
name?: string;
|
|
1781
1781
|
|
|
1782
|
+
/** tab color */
|
|
1783
|
+
tab_color?: Color;
|
|
1784
|
+
|
|
1782
1785
|
/** current active selection */
|
|
1783
1786
|
selection: SerializedGridSelection;
|
|
1784
1787
|
|
package/package.json
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
|
|
23
|
+
|
|
22
24
|
/**
|
|
23
25
|
* utility functions, primarily for adjusting lightness. since we generally
|
|
24
26
|
* traffic in RGB (or symbolic colors) that requires translating to/from HSL.
|
|
@@ -120,5 +122,35 @@ export const ColorFunctions = {
|
|
|
120
122
|
return p;
|
|
121
123
|
},
|
|
122
124
|
|
|
125
|
+
////////////////
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
GetLuminance: (r: number, g: number, b: number): number => {
|
|
129
|
+
const a = [r, g, b].map(v => {
|
|
130
|
+
v /= 255;
|
|
131
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
132
|
+
});
|
|
133
|
+
return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
GetContrastRatio: (data: [number, number]): number => {
|
|
137
|
+
data.sort((a, b) => b - a);
|
|
138
|
+
return (data[0] + 0.05) / (data[1] + 0.05);
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
GetTextColor: (background: [number, number, number], a: [number, number, number], b: [number, number, number]) => {
|
|
142
|
+
|
|
143
|
+
const luminance = ColorFunctions.GetLuminance(...background);
|
|
144
|
+
const luminance_a = ColorFunctions.GetLuminance(...a);
|
|
145
|
+
const luminance_b = ColorFunctions.GetLuminance(...b);
|
|
146
|
+
|
|
147
|
+
const contrast_a = ColorFunctions.GetContrastRatio([luminance_a, luminance]);
|
|
148
|
+
const contrast_b = ColorFunctions.GetContrastRatio([luminance_b, luminance]);
|
|
149
|
+
|
|
150
|
+
return contrast_a > contrast_b ? a : b;
|
|
151
|
+
},
|
|
152
|
+
|
|
123
153
|
};
|
|
124
154
|
|
|
155
|
+
|
|
156
|
+
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { CellStyle } from './style';
|
|
22
|
+
import type { CellStyle, Color } from './style';
|
|
23
23
|
import type { SerializedValueType } from './value-type';
|
|
24
24
|
import type { IArea } from './area';
|
|
25
25
|
import type { AnnotationLayout } from './layout';
|
|
@@ -64,14 +64,13 @@ export interface ImportedSheetData {
|
|
|
64
64
|
// optional, for backcompat
|
|
65
65
|
sheet_style?: number;
|
|
66
66
|
column_styles?: number[];
|
|
67
|
-
|
|
68
67
|
row_styles?: number[];
|
|
69
68
|
|
|
70
|
-
// new
|
|
71
69
|
annotations?: AnchoredAnnotation[];
|
|
70
|
+
outline?: number[];
|
|
72
71
|
|
|
73
72
|
// new
|
|
74
|
-
|
|
73
|
+
tab_color?: Color;
|
|
75
74
|
|
|
76
75
|
hidden?: boolean;
|
|
77
76
|
|
|
@@ -21,7 +21,10 @@
|
|
|
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';
|
|
27
|
+
import { Measurement } from 'treb-utils';
|
|
25
28
|
|
|
26
29
|
/*
|
|
27
30
|
* so this is a little strange. we use CSS to populate a theme object,
|
|
@@ -106,7 +109,7 @@ export interface Theme {
|
|
|
106
109
|
theme_colors?: string[];
|
|
107
110
|
|
|
108
111
|
/** as RGB, so we can adjust them */
|
|
109
|
-
theme_colors_rgb?: number
|
|
112
|
+
theme_colors_rgb?: [number, number, number][];
|
|
110
113
|
|
|
111
114
|
/**
|
|
112
115
|
* cache tinted colors. the way this works is we index by the
|
|
@@ -206,7 +209,8 @@ const TintedColor = (theme: Theme, source: ThemeColor) => {
|
|
|
206
209
|
let color = theme.tint_cache[index][tint];
|
|
207
210
|
if (!color) {
|
|
208
211
|
|
|
209
|
-
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
|
+
|
|
210
214
|
let tinted: {r: number, g: number, b: number};
|
|
211
215
|
if (tint > 0) {
|
|
212
216
|
tinted = ColorFunctions.Lighten(rgb[0], rgb[1], rgb[2], tint * 100, true);
|
|
@@ -215,6 +219,21 @@ const TintedColor = (theme: Theme, source: ThemeColor) => {
|
|
|
215
219
|
tinted = ColorFunctions.Darken(rgb[0], rgb[1], rgb[2], -tint * 100, true);
|
|
216
220
|
}
|
|
217
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
|
+
|
|
218
237
|
theme.tint_cache[index][tint] = color;
|
|
219
238
|
|
|
220
239
|
}
|
|
@@ -242,7 +261,15 @@ export const ResolveThemeColor = (theme: Theme, color?: Color, default_index?: n
|
|
|
242
261
|
return '';
|
|
243
262
|
}
|
|
244
263
|
|
|
245
|
-
|
|
264
|
+
let resolved = '';
|
|
265
|
+
|
|
266
|
+
if (IsHTMLColor(color.offset)) {
|
|
267
|
+
const clamped = Measurement.MeasureColor(color.offset.text);
|
|
268
|
+
resolved = `rgb(${clamped[0]}, ${clamped[1]}, ${clamped[2]})`;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
resolved = ResolveThemeColor(theme, color.offset, undefined);
|
|
272
|
+
}
|
|
246
273
|
|
|
247
274
|
// check cache
|
|
248
275
|
if (theme.offset_cache && theme.offset_cache[resolved]) {
|
|
@@ -253,17 +280,35 @@ export const ResolveThemeColor = (theme: Theme, color?: Color, default_index?: n
|
|
|
253
280
|
|
|
254
281
|
if (resolved) {
|
|
255
282
|
// ok figure it out?
|
|
256
|
-
const match = resolved.match(/rgb\((\d+)
|
|
283
|
+
const match = resolved.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
257
284
|
if (match) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
285
|
+
|
|
286
|
+
type ColorTuple = [number, number, number];
|
|
287
|
+
|
|
288
|
+
const background: ColorTuple = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
// const hsl = ColorFunctions.RGBToHSL(r, g, b);
|
|
292
|
+
// const check = ColorFunctions.GetLuminance(r, g, b);
|
|
293
|
+
|
|
294
|
+
const a = Array.from(Measurement.MeasureColor(theme.offset_dark)) as ColorTuple;
|
|
295
|
+
const b = Array.from(Measurement.MeasureColor(theme.offset_light)) as ColorTuple;
|
|
296
|
+
|
|
297
|
+
const tc = ColorFunctions.GetTextColor(background, a, b);
|
|
298
|
+
|
|
299
|
+
offset = `rgb(${tc[0]}, ${tc[1]}, ${tc[2]})`;
|
|
300
|
+
|
|
301
|
+
/*
|
|
302
|
+
if (hsl.l >.65)) {
|
|
261
303
|
offset = theme.offset_dark;
|
|
262
304
|
}
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
|
|
263
308
|
}
|
|
264
309
|
else {
|
|
265
310
|
// ...
|
|
266
|
-
console.warn(`can't offset against color`, resolved);
|
|
311
|
+
console.warn(`can't offset against color`, resolved, '(1)');
|
|
267
312
|
}
|
|
268
313
|
|
|
269
314
|
if (!theme.offset_cache) {
|
|
@@ -272,7 +317,7 @@ export const ResolveThemeColor = (theme: Theme, color?: Color, default_index?: n
|
|
|
272
317
|
theme.offset_cache[resolved] = offset;
|
|
273
318
|
}
|
|
274
319
|
else {
|
|
275
|
-
console.warn(`can't resolve offset color`, color.offset);
|
|
320
|
+
console.warn(`can't resolve offset color`, color.offset, '(2)');
|
|
276
321
|
}
|
|
277
322
|
|
|
278
323
|
return offset;
|
|
@@ -597,7 +642,7 @@ export const LoadThemeProperties = (container: HTMLElement): Theme => {
|
|
|
597
642
|
context.fillStyle = color;
|
|
598
643
|
context.fillRect(0, 0, 3, 3);
|
|
599
644
|
const imagedata = context.getImageData(1, 1, 1, 1);
|
|
600
|
-
return Array.from(imagedata.data);
|
|
645
|
+
return Array.from(imagedata.data) as [number, number, number];
|
|
601
646
|
});
|
|
602
647
|
}
|
|
603
648
|
|
|
@@ -55,20 +55,64 @@
|
|
|
55
55
|
* of times we have to define the same colors.
|
|
56
56
|
*/
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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 {
|
|
@@ -145,6 +145,8 @@ export class Sheet {
|
|
|
145
145
|
|
|
146
146
|
public name = Sheet.default_sheet_name;
|
|
147
147
|
|
|
148
|
+
public tab_color?: Color;
|
|
149
|
+
|
|
148
150
|
public background_image?: string;
|
|
149
151
|
|
|
150
152
|
protected _image: HTMLImageElement|undefined = undefined;
|
|
@@ -403,6 +405,9 @@ export class Sheet {
|
|
|
403
405
|
if (source.name) {
|
|
404
406
|
sheet.name = source.name;
|
|
405
407
|
}
|
|
408
|
+
if (source.tab_color) {
|
|
409
|
+
sheet.tab_color = source.tab_color;
|
|
410
|
+
}
|
|
406
411
|
|
|
407
412
|
if (source.background_image) {
|
|
408
413
|
sheet.background_image = source.background_image;
|
|
@@ -2744,6 +2749,7 @@ export class Sheet {
|
|
|
2744
2749
|
|
|
2745
2750
|
id: this.id,
|
|
2746
2751
|
name: this.name,
|
|
2752
|
+
tab_color: this.tab_color,
|
|
2747
2753
|
|
|
2748
2754
|
data,
|
|
2749
2755
|
sheet_style,
|
|
@@ -2915,7 +2921,11 @@ export class Sheet {
|
|
|
2915
2921
|
// this.cells.FromJSON(cell_data);
|
|
2916
2922
|
this.cells.FromJSON(data.cells);
|
|
2917
2923
|
if (data.name) {
|
|
2918
|
-
this.name = data.name || '';
|
|
2924
|
+
this.name = data.name || ''; // wtf is this?
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
if (data.tab_color) {
|
|
2928
|
+
this.tab_color = data.tab_color;
|
|
2919
2929
|
}
|
|
2920
2930
|
|
|
2921
2931
|
// 0 is implicitly just a general style
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { IArea, SerializedCellData, CellStyle } from 'treb-base-types';
|
|
22
|
+
import type { IArea, SerializedCellData, CellStyle, Color } from 'treb-base-types';
|
|
23
23
|
import type { AnnotationData } from './annotation';
|
|
24
24
|
import type { GridSelection, SerializedGridSelection } from './sheet_selection';
|
|
25
25
|
import type { ConditionalFormatList } from './conditional_format';
|
|
@@ -126,6 +126,9 @@ export interface SerializedSheet {
|
|
|
126
126
|
/** sheet name */
|
|
127
127
|
name?: string;
|
|
128
128
|
|
|
129
|
+
/** tab color */
|
|
130
|
+
tab_color?: Color;
|
|
131
|
+
|
|
129
132
|
/** current active selection */
|
|
130
133
|
selection: SerializedGridSelection;
|
|
131
134
|
|
|
@@ -437,6 +437,22 @@ $text-reference-color-5: rgb(254, 47, 1);
|
|
|
437
437
|
&[selected] {
|
|
438
438
|
background: var(--treb-tab-bar-active-tab-background, #fff);
|
|
439
439
|
color: var(--treb-tab-bar-active-tab-color, var(--treb-ui-color, inherit));
|
|
440
|
+
|
|
441
|
+
border-bottom-color: var(--treb-tab-bar-active-tab-border-color, currentColor);
|
|
442
|
+
|
|
443
|
+
/*
|
|
444
|
+
position: relative;
|
|
445
|
+
&::after {
|
|
446
|
+
content: '';
|
|
447
|
+
position: absolute;
|
|
448
|
+
bottom: 0px;
|
|
449
|
+
left: 0px;
|
|
450
|
+
width: 100%;
|
|
451
|
+
height: 1px;
|
|
452
|
+
background: currentColor;
|
|
453
|
+
}
|
|
454
|
+
*/
|
|
455
|
+
|
|
440
456
|
}
|
|
441
457
|
}
|
|
442
458
|
|
|
@@ -439,13 +439,7 @@ export class Exporter {
|
|
|
439
439
|
|
|
440
440
|
const dxf: DOMContent[] = style_cache.dxf_styles.map(style => {
|
|
441
441
|
|
|
442
|
-
const entry: DOMContent = {
|
|
443
|
-
fill: style.fill ? {
|
|
444
|
-
patternFill: {
|
|
445
|
-
bgColor: ColorAttrs(style.fill),
|
|
446
|
-
},
|
|
447
|
-
} : undefined,
|
|
448
|
-
};
|
|
442
|
+
const entry: DOMContent = {};
|
|
449
443
|
|
|
450
444
|
if (style.text || style.bold || style.italic || style.underline) {
|
|
451
445
|
entry.font = {
|
|
@@ -457,6 +451,14 @@ export class Exporter {
|
|
|
457
451
|
};
|
|
458
452
|
}
|
|
459
453
|
|
|
454
|
+
if (style.fill) {
|
|
455
|
+
entry.fill = {
|
|
456
|
+
patternFill: {
|
|
457
|
+
bgColor: ColorAttrs(style.fill),
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
460
462
|
return entry;
|
|
461
463
|
|
|
462
464
|
});
|
|
@@ -2214,6 +2216,34 @@ export class Exporter {
|
|
|
2214
2216
|
// delete dom.worksheet.drawing;
|
|
2215
2217
|
}
|
|
2216
2218
|
|
|
2219
|
+
// --- tab color ---------------------------------------------------------
|
|
2220
|
+
|
|
2221
|
+
const tab_color_block: DOMContent = {};
|
|
2222
|
+
if (sheet.tab_color) {
|
|
2223
|
+
if (IsThemeColor(sheet.tab_color)) {
|
|
2224
|
+
tab_color_block.sheetPr = {
|
|
2225
|
+
tabColor: {
|
|
2226
|
+
a$: {
|
|
2227
|
+
theme: sheet.tab_color.theme,
|
|
2228
|
+
tint: sheet.tab_color.tint,
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
else if (IsHTMLColor(sheet.tab_color)) {
|
|
2234
|
+
const color = sheet.tab_color.text || '';
|
|
2235
|
+
if (/^#[0-9a-fA-F]*$/.test(color)) {
|
|
2236
|
+
tab_color_block.sheetPr = {
|
|
2237
|
+
tabColor: {
|
|
2238
|
+
a$: {
|
|
2239
|
+
rgb: `FF` + color.substring(1)
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2217
2247
|
// --- move page margins -------------------------------------------------
|
|
2218
2248
|
|
|
2219
2249
|
// const margins = dom.worksheet.pageMargins;
|
|
@@ -2242,6 +2272,9 @@ export class Exporter {
|
|
|
2242
2272
|
|
|
2243
2273
|
worksheet: {
|
|
2244
2274
|
a$: { ...sheet_attributes },
|
|
2275
|
+
|
|
2276
|
+
...tab_color_block,
|
|
2277
|
+
|
|
2245
2278
|
dimension: {
|
|
2246
2279
|
a$: {
|
|
2247
2280
|
ref: new Area(extent.start, extent.end).spreadsheet_label,
|