@trebco/treb 30.16.0 → 31.0.2
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/api-generator/api-generator.ts +3 -1
- package/api-generator/package.json +2 -1
- package/dist/treb-export-worker.mjs +2 -2
- package/dist/treb-spreadsheet.mjs +13 -13
- package/dist/treb.d.ts +19 -2
- package/package.json +8 -7
- package/treb-base-types/src/font-stack.ts +144 -0
- package/treb-base-types/src/style.ts +121 -11
- package/treb-base-types/src/theme.ts +53 -8
- package/treb-calculator/src/calculator.ts +13 -13
- package/treb-calculator/src/descriptors.ts +12 -4
- package/treb-calculator/src/expression-calculator.ts +17 -4
- package/treb-calculator/src/functions/base-functions.ts +57 -4
- package/treb-calculator/src/functions/statistics-functions.ts +9 -6
- package/treb-calculator/tsconfig.json +11 -0
- package/treb-charts/style/charts.scss +7 -1
- package/treb-data-model/src/annotation.ts +6 -0
- package/treb-data-model/src/data_model.ts +14 -3
- package/treb-data-model/src/sheet.ts +57 -56
- package/treb-embed/markup/toolbar.html +15 -1
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +38 -0
- package/treb-embed/src/embedded-spreadsheet.ts +119 -29
- package/treb-embed/src/options.ts +3 -0
- package/treb-embed/src/selection-state.ts +1 -0
- package/treb-embed/src/toolbar-message.ts +6 -0
- package/treb-embed/src/types.ts +9 -0
- package/treb-embed/style/defaults.scss +12 -1
- package/treb-embed/style/font-stacks.scss +105 -0
- package/treb-embed/style/layout.scss +1 -0
- package/treb-embed/style/theme-defaults.scss +12 -2
- package/treb-embed/style/toolbar.scss +16 -0
- package/treb-grid/src/editors/overlay_editor.ts +36 -3
- package/treb-grid/src/layout/base_layout.ts +52 -37
- package/treb-grid/src/layout/grid_layout.ts +7 -0
- package/treb-grid/src/render/tile_renderer.ts +154 -148
- package/treb-grid/src/types/grid.ts +188 -54
- package/treb-grid/src/types/grid_events.ts +1 -1
- package/treb-grid/src/types/grid_options.ts +3 -0
- package/treb-grid/src/util/fontmetrics.ts +134 -0
- package/treb-parser/src/parser.ts +12 -3
- package/treb-utils/src/measurement.ts +2 -3
- package/tsproject.json +1 -1
- package/treb-calculator/modern.tsconfig.json +0 -11
- package/treb-grid/src/util/fontmetrics2.ts +0 -182
- package/treb-parser/src/parser.test.ts +0 -298
- /package/treb-embed/{modern.tsconfig.json → tsconfig.json} +0 -0
- /package/treb-export/{modern.tsconfig.json → tsconfig.json} +0 -0
|
@@ -41,6 +41,8 @@ import { CoerceComplex } from './function-utilities';
|
|
|
41
41
|
import type { UnitAddress, UnitRange } from 'treb-parser';
|
|
42
42
|
import { ConstructDate } from './date-utils';
|
|
43
43
|
|
|
44
|
+
// import type { CalculationContext } from '../descriptors';
|
|
45
|
+
|
|
44
46
|
/**
|
|
45
47
|
* BaseFunctionLibrary is a static object that has basic spreadsheet
|
|
46
48
|
* functions and associated metadata (there's also a list of aliases).
|
|
@@ -1253,10 +1255,35 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1253
1255
|
},
|
|
1254
1256
|
*/
|
|
1255
1257
|
|
|
1256
|
-
|
|
1257
1258
|
Row: {
|
|
1258
1259
|
arguments: [{ name: 'reference', metadata: true }],
|
|
1259
|
-
fn: (ref
|
|
1260
|
+
fn: function(ref?: UnionValue): UnionValue {
|
|
1261
|
+
|
|
1262
|
+
if (!ref) {
|
|
1263
|
+
if (this?.area) {
|
|
1264
|
+
const value: UnionValue[][] = [];
|
|
1265
|
+
for (let c = this.area.start.column; c <= this.area.end.column; c++) {
|
|
1266
|
+
const col: UnionValue[] = [];
|
|
1267
|
+
for (let r = this.area.start.row; r <= this.area.end.row; r++) {
|
|
1268
|
+
col.push({
|
|
1269
|
+
type: ValueType.number,
|
|
1270
|
+
value: r + 1,
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
value.push(col);
|
|
1274
|
+
}
|
|
1275
|
+
return {
|
|
1276
|
+
type: ValueType.array, value,
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
else {
|
|
1280
|
+
return {
|
|
1281
|
+
type: ValueType.number,
|
|
1282
|
+
value: this ? this.address.row + 1 : -1,
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1260
1287
|
if (ref.type === ValueType.array) {
|
|
1261
1288
|
const arr = ref.value;
|
|
1262
1289
|
const first = arr[0][0];
|
|
@@ -1283,7 +1310,33 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1283
1310
|
|
|
1284
1311
|
Column: {
|
|
1285
1312
|
arguments: [{ name: 'reference', metadata: true }],
|
|
1286
|
-
fn: (ref
|
|
1313
|
+
fn: function(ref?: UnionValue): UnionValue {
|
|
1314
|
+
|
|
1315
|
+
if (!ref) {
|
|
1316
|
+
if (this?.area) {
|
|
1317
|
+
const value: UnionValue[][] = [];
|
|
1318
|
+
for (let c = this.area.start.column; c <= this.area.end.column; c++) {
|
|
1319
|
+
const col: UnionValue[] = [];
|
|
1320
|
+
for (let r = this.area.start.row; r <= this.area.end.row; r++) {
|
|
1321
|
+
col.push({
|
|
1322
|
+
type: ValueType.number,
|
|
1323
|
+
value: c + 1,
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
value.push(col);
|
|
1327
|
+
}
|
|
1328
|
+
return {
|
|
1329
|
+
type: ValueType.array, value,
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
else {
|
|
1333
|
+
return {
|
|
1334
|
+
type: ValueType.number,
|
|
1335
|
+
value: this ? this.address.column + 1 : -1,
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1287
1340
|
if (ref.type === ValueType.array) {
|
|
1288
1341
|
const arr = ref.value;
|
|
1289
1342
|
const first = arr[0][0];
|
|
@@ -1307,7 +1360,7 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1307
1360
|
return ArgumentError();
|
|
1308
1361
|
},
|
|
1309
1362
|
},
|
|
1310
|
-
|
|
1363
|
+
|
|
1311
1364
|
Choose: {
|
|
1312
1365
|
arguments: [
|
|
1313
1366
|
{ name: 'Selected index', },
|
|
@@ -409,6 +409,7 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
409
409
|
},
|
|
410
410
|
},
|
|
411
411
|
|
|
412
|
+
/* use alias instead
|
|
412
413
|
'NormsInv': {
|
|
413
414
|
|
|
414
415
|
description: 'Inverse of the normal cumulative distribution',
|
|
@@ -423,7 +424,8 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
423
424
|
}
|
|
424
425
|
}
|
|
425
426
|
},
|
|
426
|
-
|
|
427
|
+
*/
|
|
428
|
+
|
|
427
429
|
'Norm.Inv': {
|
|
428
430
|
description: 'Inverse of the normal cumulative distribution',
|
|
429
431
|
arguments: [
|
|
@@ -441,17 +443,15 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
441
443
|
},
|
|
442
444
|
|
|
443
445
|
'Norm.S.Inv': {
|
|
444
|
-
description: 'Inverse of the normal cumulative distribution',
|
|
446
|
+
description: 'Inverse of the standard normal cumulative distribution',
|
|
445
447
|
arguments: [
|
|
446
448
|
{name: 'probability'},
|
|
447
|
-
{name: 'mean', default: 0},
|
|
448
|
-
{name: 'standard deviation', default: 1},
|
|
449
449
|
],
|
|
450
450
|
xlfn: true,
|
|
451
|
-
fn: (q: number
|
|
451
|
+
fn: (q: number): UnionValue => {
|
|
452
452
|
return {
|
|
453
453
|
type: ValueType.number,
|
|
454
|
-
value: inverse_normal(q)
|
|
454
|
+
value: inverse_normal(q),
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
457
|
},
|
|
@@ -1073,4 +1073,7 @@ export const StatisticsFunctionAliases: {[index: string]: string} = {
|
|
|
1073
1073
|
'StDevPA': 'StDev.P',
|
|
1074
1074
|
'Var': 'Var.S',
|
|
1075
1075
|
'Quartile': 'Quartile.Inc',
|
|
1076
|
+
'NormSInv': 'Norm.S.Inv',
|
|
1077
|
+
'NormSDist': 'Norm.S.Dist',
|
|
1078
|
+
|
|
1076
1079
|
};
|
|
@@ -43,8 +43,14 @@
|
|
|
43
43
|
// this was getting lost by the new higher-specificity reset
|
|
44
44
|
background: var(--treb-chart-background, #fff);
|
|
45
45
|
|
|
46
|
-
}
|
|
46
|
+
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* new override allows inheriting fonts in annotations (at least for charts)
|
|
50
|
+
*/
|
|
51
|
+
.treb-main.treb-main .treb-inherit-font .treb-chart {
|
|
52
|
+
font-family: inherit;
|
|
53
|
+
}
|
|
48
54
|
|
|
49
55
|
/* container style */
|
|
50
56
|
.treb-chart {
|
|
@@ -117,6 +117,12 @@ export interface AnnotationDataBase {
|
|
|
117
117
|
/** the new layout, persisted and takes preference over the old one */
|
|
118
118
|
layout?: AnnotationLayout;
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* adding cell style as a convenient store for font stack; atm we are
|
|
122
|
+
* ignoring everything but the font_face attribute
|
|
123
|
+
*/
|
|
124
|
+
style?: CellStyle;
|
|
125
|
+
|
|
120
126
|
/**
|
|
121
127
|
* the old layout used rectangles, and we need to keep support for
|
|
122
128
|
* that. this is not the layout rectangle. this rectangle is just
|
|
@@ -435,8 +435,8 @@ export class DataModel {
|
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
/** wrapper method ensures it always returns an Area (instance, not interface) */
|
|
438
|
-
public ResolveArea(address: string|ICellAddress|IArea, active_sheet: Sheet): Area {
|
|
439
|
-
const resolved = this.ResolveAddress(address, active_sheet);
|
|
438
|
+
public ResolveArea(address: string|ICellAddress|IArea, active_sheet: Sheet, options?: { r1c1?: boolean }): Area {
|
|
439
|
+
const resolved = this.ResolveAddress(address, active_sheet, options);
|
|
440
440
|
return IsCellAddress(resolved) ? new Area(resolved) : new Area(resolved.start, resolved.end);
|
|
441
441
|
}
|
|
442
442
|
|
|
@@ -449,10 +449,21 @@ export class DataModel {
|
|
|
449
449
|
* Q: why are we not preserving absoute/relative? (...)
|
|
450
450
|
*
|
|
451
451
|
*/
|
|
452
|
-
public ResolveAddress(address: string|ICellAddress|IArea, active_sheet: Sheet): ICellAddress|IArea {
|
|
452
|
+
public ResolveAddress(address: string|ICellAddress|IArea, active_sheet: Sheet, options? : { r1c1?: boolean }): ICellAddress|IArea {
|
|
453
453
|
|
|
454
454
|
if (typeof address === 'string') {
|
|
455
|
+
|
|
456
|
+
if (options?.r1c1) {
|
|
457
|
+
this.parser.Save();
|
|
458
|
+
this.parser.flags.r1c1 = true;
|
|
459
|
+
}
|
|
460
|
+
|
|
455
461
|
const parse_result = this.parser.Parse(address);
|
|
462
|
+
|
|
463
|
+
if (options?.r1c1) {
|
|
464
|
+
this.parser.Restore();
|
|
465
|
+
}
|
|
466
|
+
|
|
456
467
|
if (parse_result.expression && parse_result.expression.type === 'address') {
|
|
457
468
|
this.ResolveSheetID(parse_result.expression, undefined, active_sheet);
|
|
458
469
|
return {
|
|
@@ -33,7 +33,10 @@ import { Measurement, ValidateURI } from 'treb-utils';
|
|
|
33
33
|
|
|
34
34
|
import type { TextPart ,
|
|
35
35
|
Cell, ICellAddress, CellSerializationOptions, CellValue, ImportedSheetData, Complex,
|
|
36
|
-
DimensionedQuantity, IArea, Table, TableTheme, HorizontalAlign, VerticalAlign
|
|
36
|
+
DimensionedQuantity, IArea, Table, TableTheme, HorizontalAlign, VerticalAlign,
|
|
37
|
+
Theme} from 'treb-base-types';
|
|
38
|
+
|
|
39
|
+
import { Get as GetFonrMetrics } from 'treb-grid/src/util/fontmetrics';
|
|
37
40
|
|
|
38
41
|
// --- local imports ----------------------------------------------------------
|
|
39
42
|
|
|
@@ -299,7 +302,8 @@ export class Sheet {
|
|
|
299
302
|
|
|
300
303
|
this.default_column_width = DEFAULT_COLUMN_WIDTH;
|
|
301
304
|
this.row_header_width = DEFAULT_ROW_HEADER_WIDTH;
|
|
302
|
-
|
|
305
|
+
|
|
306
|
+
// this.UpdateDefaultRowHeight();
|
|
303
307
|
|
|
304
308
|
this.id_ = Sheet.base_id++;
|
|
305
309
|
|
|
@@ -314,10 +318,14 @@ export class Sheet {
|
|
|
314
318
|
/**
|
|
315
319
|
* factory method creates a new sheet
|
|
316
320
|
*/
|
|
317
|
-
public static Blank(style_defaults: CellStyle, name?: string, rows = 30, columns = 20): Sheet {
|
|
321
|
+
public static Blank(style_defaults: CellStyle, name?: string, rows = 30, columns = 20, theme?: Theme): Sheet {
|
|
318
322
|
|
|
319
323
|
const sheet = new Sheet(style_defaults);
|
|
320
324
|
|
|
325
|
+
if (theme) {
|
|
326
|
+
sheet.UpdateDefaultRowHeight(theme);
|
|
327
|
+
}
|
|
328
|
+
|
|
321
329
|
if (name) {
|
|
322
330
|
sheet.name = name;
|
|
323
331
|
}
|
|
@@ -905,71 +913,45 @@ export class Sheet {
|
|
|
905
913
|
|
|
906
914
|
}
|
|
907
915
|
|
|
908
|
-
/**
|
|
909
|
-
* FIXME: measure the font.
|
|
910
|
-
*
|
|
911
|
-
* Can we use the same metrics as renderer? That uses a canvas. Obviously
|
|
912
|
-
* canvas won't work if there's no DOM but it's OK if this method fails in
|
|
913
|
-
* that case; the only question is will it break if it's running headless?
|
|
914
|
-
*/
|
|
915
|
-
public StyleFontSize(style: CellStyle, default_properties: CellStyle = {}): number {
|
|
916
|
-
|
|
917
|
-
let font_height = (style.font_size?.value || 0);
|
|
918
|
-
|
|
919
|
-
let scale = 0;
|
|
920
|
-
|
|
921
|
-
switch (style.font_size?.unit) {
|
|
922
|
-
case 'px':
|
|
923
|
-
font_height *= (75 / 100);
|
|
924
|
-
break;
|
|
925
|
-
|
|
926
|
-
case 'em':
|
|
927
|
-
scale = style.font_size.value || 1;
|
|
928
|
-
break;
|
|
929
|
-
|
|
930
|
-
case '%':
|
|
931
|
-
scale = (style.font_size.value || 100) / 100;
|
|
932
|
-
break;
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
if (scale) {
|
|
936
|
-
font_height = scale * (default_properties.font_size?.value || 10);
|
|
937
|
-
if (default_properties.font_size?.unit === 'px') {
|
|
938
|
-
font_height *= (75 / 100);
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
return font_height || 10;
|
|
943
|
-
|
|
944
|
-
}
|
|
945
|
-
|
|
946
916
|
/**
|
|
947
917
|
* FIXME: this is called in the ctor, which made sense when sheets
|
|
948
918
|
* were more ephemeral. now that we update a single instance, rather
|
|
949
919
|
* than create new instances, we lose this behavior. we should call
|
|
950
920
|
* this when we change sheet style.
|
|
951
921
|
*
|
|
952
|
-
*
|
|
922
|
+
* actually this should just move to theme, no? as long as sheet has
|
|
923
|
+
* a reference to theme. for headless instances that would just use
|
|
924
|
+
* theme defaults, which should be appropriate.
|
|
925
|
+
*
|
|
926
|
+
* I guess the original idea was that sheet style might be used to
|
|
927
|
+
* base row height on sheet font size? not sure if that's how it actually
|
|
928
|
+
* plays out, since this is only called in the ctor (or equivalent) or when
|
|
929
|
+
* theme is updated (but not when sheet style is updated). might need some
|
|
930
|
+
* thought.
|
|
931
|
+
*
|
|
953
932
|
*/
|
|
954
|
-
public UpdateDefaultRowHeight(): void {
|
|
933
|
+
public UpdateDefaultRowHeight(theme: Theme, scale = 1): void {
|
|
955
934
|
|
|
956
|
-
|
|
935
|
+
// this guard is here because this is called by sheet directly, so maybe
|
|
936
|
+
// in headless context? would make more sense to just not call it
|
|
957
937
|
|
|
958
938
|
if (typeof window !== 'undefined') {
|
|
959
939
|
|
|
960
|
-
const
|
|
961
|
-
const
|
|
940
|
+
const composite = Style.Composite([this.default_style_properties, this.sheet_style]);
|
|
941
|
+
const font_info = Style.CompositeFont(theme.grid_cell_font_size, composite, scale, theme);
|
|
942
|
+
const metrics = GetFonrMetrics(font_info.font, font_info.variants);
|
|
943
|
+
const height = metrics.height * 1.25; // ??
|
|
944
|
+
|
|
945
|
+
// const measurement = Measurement.MeasureText(Style.Font2(composite, 1, theme).font, 'M');
|
|
946
|
+
// const height = Math.round(measurement.height * 1.4);
|
|
947
|
+
|
|
948
|
+
// console.info({height, default: this.default_row_height});
|
|
962
949
|
|
|
963
950
|
if (this.default_row_height < height) {
|
|
964
951
|
this.default_row_height = height;
|
|
965
952
|
}
|
|
966
953
|
|
|
967
954
|
}
|
|
968
|
-
/*
|
|
969
|
-
else {
|
|
970
|
-
// console.info('worker?');
|
|
971
|
-
}
|
|
972
|
-
*/
|
|
973
955
|
|
|
974
956
|
}
|
|
975
957
|
|
|
@@ -1658,14 +1640,14 @@ export class Sheet {
|
|
|
1658
1640
|
this.column_header_height = column_header_height;
|
|
1659
1641
|
}
|
|
1660
1642
|
|
|
1661
|
-
|
|
1643
|
+
/* *
|
|
1662
1644
|
* resize row to match character hight, taking into
|
|
1663
1645
|
* account multi-line values.
|
|
1664
1646
|
*
|
|
1665
1647
|
* UPDATE: since the only caller calls with inline = true, removing
|
|
1666
1648
|
* parameter, test, and extra behavior.
|
|
1667
|
-
|
|
1668
|
-
public AutoSizeRow(row: number,
|
|
1649
|
+
* /
|
|
1650
|
+
public AutoSizeRow(row: number, theme?: Theme, allow_shrink = true, scale = 1): void {
|
|
1669
1651
|
|
|
1670
1652
|
let height = this.default_row_height;
|
|
1671
1653
|
const padding = 9; // 9?
|
|
@@ -1673,7 +1655,7 @@ export class Sheet {
|
|
|
1673
1655
|
for (let column = 0; column < this.cells.columns; column++) {
|
|
1674
1656
|
|
|
1675
1657
|
const cell = this.CellData({ row, column });
|
|
1676
|
-
const style = cell.style;
|
|
1658
|
+
const style = JSON.parse(JSON.stringify(cell.style));
|
|
1677
1659
|
let text = cell.formatted || '';
|
|
1678
1660
|
|
|
1679
1661
|
if (typeof text !== 'string') {
|
|
@@ -1682,7 +1664,25 @@ export class Sheet {
|
|
|
1682
1664
|
|
|
1683
1665
|
if (style && text && text.length) {
|
|
1684
1666
|
const lines = text.split(/\n/);
|
|
1685
|
-
|
|
1667
|
+
|
|
1668
|
+
if (style.font_size) {
|
|
1669
|
+
if (style.font_size.unit === 'em') {
|
|
1670
|
+
const base = theme?.grid_cell_font_size || { unit: 'pt', value: 10 };
|
|
1671
|
+
style.font_size.unit = base.unit;
|
|
1672
|
+
style.font_size.value *= base.value;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
else {
|
|
1676
|
+
style.font_size = theme?.grid_cell_font_size || { unit: 'pt', value: 10 };
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
let target = style.font_size.value;
|
|
1680
|
+
if (style.font_size.unit === 'px') {
|
|
1681
|
+
target = Math.round((style.font_size.value||16) * 300 / 4) / 100;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
const font_height = // Math.round(this.StyleFontSize(style, default_properties) * 1.5); // it's a start, we still need to measure properly
|
|
1685
|
+
Math.round(target * 1.5 * scale);
|
|
1686
1686
|
height = Math.max(height, ((font_height || 10) + padding) * lines.length);
|
|
1687
1687
|
}
|
|
1688
1688
|
}
|
|
@@ -1695,6 +1695,7 @@ export class Sheet {
|
|
|
1695
1695
|
this.SetRowHeight(row, height);
|
|
1696
1696
|
|
|
1697
1697
|
}
|
|
1698
|
+
*/
|
|
1698
1699
|
|
|
1699
1700
|
/** returns the style properties for a given style index */
|
|
1700
1701
|
public GetStyle(index: number): CellStyle {
|
|
@@ -130,13 +130,27 @@
|
|
|
130
130
|
<button data-command="font-scale" data-scale="0.9">0.90</button>
|
|
131
131
|
<button data-command="font-scale" data-scale="1.0">1.00</button>
|
|
132
132
|
<button data-command="font-scale" data-scale="1.1">1.10</button>
|
|
133
|
-
<button data-command="font-scale" data-scale="1.
|
|
133
|
+
<button data-command="font-scale" data-scale="1.25">1.25</button>
|
|
134
134
|
<button data-command="font-scale" data-scale="1.5">1.50</button>
|
|
135
135
|
<button data-command="font-scale" data-scale="2.0">2.00</button>
|
|
136
136
|
</div>
|
|
137
137
|
</div>
|
|
138
138
|
</div>
|
|
139
139
|
|
|
140
|
+
<div composite font-stack>
|
|
141
|
+
<button class="treb-font-stack" data-command="font-stack" data-font-stack="" title="Font stack"></button>
|
|
142
|
+
<div class="treb-menu">
|
|
143
|
+
<button dropdown title="Font stack options"></button>
|
|
144
|
+
<div>
|
|
145
|
+
<button data-command="font-stack" data-font-stack="default"></button>
|
|
146
|
+
<button data-command="font-stack" data-font-stack="transitional"></button>
|
|
147
|
+
<button data-command="font-stack" data-font-stack="monospace"></button>
|
|
148
|
+
<button data-command="font-stack" data-font-stack="handwritten"></button>
|
|
149
|
+
<button data-command="font-stack" data-font-stack="ui"></button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
140
154
|
<div composite>
|
|
141
155
|
<input class="treb-number-format" title="Number format">
|
|
142
156
|
<div class="treb-menu">
|
|
@@ -12,6 +12,7 @@ import { Measurement } from 'treb-utils';
|
|
|
12
12
|
import type { ToolbarMessage } from '../toolbar-message';
|
|
13
13
|
|
|
14
14
|
import { DOMContext } from 'treb-base-types';
|
|
15
|
+
import { font_stack_labels, type FontStackType } from 'treb-base-types/src/font-stack';
|
|
15
16
|
|
|
16
17
|
/** with a view towards i18n */
|
|
17
18
|
const default_titles: Record<string, string> = {
|
|
@@ -668,6 +669,24 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
668
669
|
}
|
|
669
670
|
}
|
|
670
671
|
|
|
672
|
+
if (this.toolbar_controls.stack) {
|
|
673
|
+
if (state.style?.font_face) {
|
|
674
|
+
if (state.style.font_face.startsWith('stack:')) {
|
|
675
|
+
const stack_name = state.style.font_face.substring(6) as FontStackType;
|
|
676
|
+
this.toolbar_controls.stack.textContent = font_stack_labels[stack_name] || '';
|
|
677
|
+
this.toolbar_controls.stack.dataset.fontStack = stack_name;
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
this.toolbar_controls.stack.textContent = '';
|
|
681
|
+
this.toolbar_controls.stack.dataset.fontStack = '';
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
else { // } if (!state.empty) {
|
|
685
|
+
this.toolbar_controls.stack.textContent = font_stack_labels.default || '';
|
|
686
|
+
this.toolbar_controls.stack.dataset.fontStack = 'default';
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
671
690
|
const format = this.toolbar_controls.format as HTMLInputElement;
|
|
672
691
|
if (format) {
|
|
673
692
|
if (state.style?.number_format) {
|
|
@@ -914,6 +933,19 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
914
933
|
if (!sheet.options.font_scale) {
|
|
915
934
|
remove.push(toolbar.querySelector('[font-scale]'));
|
|
916
935
|
}
|
|
936
|
+
if (!sheet.options.font_stack) {
|
|
937
|
+
remove.push(toolbar.querySelector('[font-stack]'));
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
const buttons = toolbar.querySelectorAll(`[font-stack] button[data-font-stack]`) as NodeListOf<HTMLElement>;
|
|
941
|
+
for (const button of buttons) {
|
|
942
|
+
if (button.dataset.fontStack) {
|
|
943
|
+
const label = font_stack_labels[button.dataset.fontStack as FontStackType];
|
|
944
|
+
button.textContent = label || '';
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
917
949
|
if (!sheet.options.chart_menu) {
|
|
918
950
|
remove.push(toolbar.querySelector('[chart-menu]'));
|
|
919
951
|
}
|
|
@@ -967,6 +999,8 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
967
999
|
'format': 'input.treb-number-format',
|
|
968
1000
|
'scale': 'input.treb-font-scale',
|
|
969
1001
|
|
|
1002
|
+
'stack': 'button.treb-font-stack',
|
|
1003
|
+
|
|
970
1004
|
})) {
|
|
971
1005
|
|
|
972
1006
|
const element = toolbar.querySelector(value) as HTMLElement;
|
|
@@ -1029,9 +1063,11 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
1029
1063
|
color?: Color;
|
|
1030
1064
|
format?: string;
|
|
1031
1065
|
scale?: string;
|
|
1066
|
+
font_stack?: string;
|
|
1032
1067
|
} = {
|
|
1033
1068
|
format: target.dataset.format,
|
|
1034
1069
|
scale: target.dataset.scale,
|
|
1070
|
+
font_stack: target.dataset.fontStack,
|
|
1035
1071
|
};
|
|
1036
1072
|
|
|
1037
1073
|
let command = target?.dataset.command;
|
|
@@ -1376,9 +1412,11 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
|
|
|
1376
1412
|
this.UpdateSelectionStyle(sheet, toolbar, comment_box);
|
|
1377
1413
|
break;
|
|
1378
1414
|
|
|
1415
|
+
case 'annotation-selection':
|
|
1379
1416
|
case 'selection':
|
|
1380
1417
|
this.UpdateSelectionStyle(sheet, toolbar, comment_box);
|
|
1381
1418
|
break;
|
|
1419
|
+
|
|
1382
1420
|
}
|
|
1383
1421
|
});
|
|
1384
1422
|
|