@trebco/treb 31.3.3 → 31.4.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.
package/dist/treb.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /*! API v31.3. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
1
+ /*! API v31.4. 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
@@ -407,6 +407,42 @@ export declare class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
407
407
  */
408
408
  ExternalEditor(config?: Partial<ExternalEditorConfig>): void;
409
409
 
410
+ /**
411
+ * @internalRemarks removing internal flag
412
+ */
413
+ ConditionalFormatDuplicateValues(range: RangeReference | undefined, options: ConditionalFormatDuplicateValuesOptions): ConditionalFormat;
414
+
415
+ /**
416
+ * @internalRemarks removing internal flag
417
+ */
418
+ ConditionalFormatGradient(range: RangeReference | undefined, options: ConditionalFormatGradientOptions | StandardGradient): ConditionalFormat;
419
+
420
+ /**
421
+ * @internalRemarks removing internal flag
422
+ */
423
+ ConditionalFormatCellMatch(range: RangeReference | undefined, options: ConditionalFormatCellMatchOptions): ConditionalFormat;
424
+
425
+ /**
426
+ * @internalRemarks removing internal flag
427
+ */
428
+ ConditionalFormatExpression(range: RangeReference | undefined, options: CondifionalFormatExpressionOptions): ConditionalFormat;
429
+
430
+ /**
431
+ * remove conditional format
432
+ *
433
+ * @internalRemarks removing internal flag
434
+ */
435
+ RemoveConditionalFormat(format: ConditionalFormat): void;
436
+
437
+ /**
438
+ * clear conditional formats from the target range (or currently selected
439
+ * range). we operate on format objects, meaning we'll remove the whole
440
+ * format object rather than clip the area.
441
+ *
442
+ * @internalRemarks removing internal flag
443
+ */
444
+ RemoveConditionalFormats(range?: RangeReference): void;
445
+
410
446
  /** dynamically load language module */
411
447
  LoadLanguage(language?: string): Promise<void>;
412
448
 
@@ -1152,42 +1188,79 @@ export interface FreezePane {
1152
1188
  rows: number;
1153
1189
  columns: number;
1154
1190
  }
1191
+ export interface CondifionalFormatExpressionOptions {
1192
+ style: CellStyle;
1193
+ expression: string;
1194
+ options?: EvaluateOptions;
1195
+ }
1196
+ export interface ConditionalFormatGradientOptions {
1155
1197
 
1156
- /**
1157
- * options for serializing data
1158
- */
1159
- export interface SerializeOptions {
1160
-
1161
- /** optimize for size */
1162
- optimize?: 'size' | 'speed';
1198
+ /** property defaults to fill */
1199
+ property?: 'fill' | 'text';
1163
1200
 
1164
- /** include the rendered/calculated value in export */
1165
- rendered_values?: boolean;
1201
+ /** defaults to RGB */
1202
+ color_space?: 'HSL' | 'RGB';
1166
1203
 
1167
- /** translate colors to xlsx-friendly values */
1168
- export_colors?: boolean;
1204
+ /** gradient stops, required */
1205
+ stops: Array<{
1206
+ value: number;
1207
+ color: Color;
1208
+ }>;
1169
1209
 
1170
- /** export cells that have no value, but have a border or background color */
1171
- decorated_cells?: boolean;
1210
+ /** min and max are optional. if not provided, we use the min/max of the range of data. */
1211
+ min?: number;
1172
1212
 
1173
- /** prune unused rows/columns */
1174
- shrink?: boolean;
1213
+ /** min and max are optional. if not provided, we use the min/max of the range of data. */
1214
+ max?: number;
1215
+ }
1216
+ export type StandardGradient = keyof typeof StandardGradientsList;
1217
+ export interface ConditionalFormatCellMatchOptions {
1218
+ style: CellStyle;
1219
+ expression: string;
1220
+ options?: EvaluateOptions;
1221
+ }
1222
+ export interface ConditionalFormatDuplicateValuesOptions {
1223
+ style: CellStyle;
1175
1224
 
1176
- /**
1177
- * include tables. tables will be serialized in the model, so we can
1178
- * drop them from cells. but you can leave them in if that's useful.
1179
- */
1180
- tables?: boolean;
1225
+ /** true to highlight unique cells, false to highlight duplicates. defaults to false. */
1226
+ unique?: boolean;
1227
+ }
1181
1228
 
1182
- /** share resources (images, for now) to prevent writing data URIs more than once */
1183
- share_resources?: boolean;
1229
+ /**
1230
+ * union, plus we're adding a state used to track application.
1231
+ * that state is serialized if it's true.
1232
+ * we also add an internal field that will be type-specific, and not serialized.
1233
+ *
1234
+ * ...everybody has a vertex now, we could standardize it
1235
+ *
1236
+ * update: adding a priority field, optional
1237
+ *
1238
+ */
1239
+ export type ConditionalFormat = {
1240
+ internal?: unknown;
1241
+ priority?: number;
1242
+ } & (ConditionalFormatDuplicateValues | ConditionalFormatExpression | ConditionalFormatCellMatch | ConditionalFormatGradient);
1184
1243
 
1185
- /**
1186
- * if a function has an export() handler, call that
1187
- */
1188
- export_functions?: boolean;
1244
+ /**
1245
+ * conditional format predicated on an expression. if the expression
1246
+ * evaluates to true, we apply the style. otherwise no.
1247
+ */
1248
+ export interface ConditionalFormatExpression extends CondifionalFormatExpressionOptions {
1249
+ type: 'expression';
1250
+ area: IArea;
1251
+ }
1252
+ export interface ConditionalFormatGradient extends ConditionalFormatGradientOptions {
1253
+ type: 'gradient';
1254
+ area: IArea;
1255
+ }
1256
+ export interface ConditionalFormatCellMatch extends ConditionalFormatCellMatchOptions {
1257
+ type: 'cell-match';
1258
+ area: IArea;
1259
+ }
1260
+ export interface ConditionalFormatDuplicateValues extends ConditionalFormatDuplicateValuesOptions {
1261
+ type: 'duplicate-values';
1262
+ area: IArea;
1189
1263
  }
1190
- export type AnnotationType = 'treb-chart' | 'image' | 'textbox' | 'external';
1191
1264
 
1192
1265
  /**
1193
1266
  * Structure represents a 2d range of cells.
@@ -1196,18 +1269,7 @@ export interface IArea {
1196
1269
  start: ICellAddress;
1197
1270
  end: ICellAddress;
1198
1271
  }
1199
- export interface Point {
1200
- x: number;
1201
- y: number;
1202
- }
1203
-
1204
- /** structure represents rectangle coordinates */
1205
- export interface IRectangle {
1206
- top: number;
1207
- left: number;
1208
- width: number;
1209
- height: number;
1210
- }
1272
+ export type Color = ThemeColor | HTMLColor | NullColor;
1211
1273
 
1212
1274
  /**
1213
1275
  * style properties applied to a single cell, row, column, or sheet.
@@ -1315,11 +1377,78 @@ export interface ThemeColor {
1315
1377
  }
1316
1378
  export interface NullColor {
1317
1379
  }
1318
- export type Color = ThemeColor | HTMLColor | NullColor;
1319
1380
  export declare const ThemeColorIndex: (color: ThemeColor) => number;
1320
1381
  export declare const IsHTMLColor: (color?: Color) => color is HTMLColor;
1321
1382
  export declare const IsThemeColor: (color?: Color) => color is ThemeColor;
1322
1383
  export declare const IsDefinedColor: (color?: Color) => color is (ThemeColor | HTMLColor);
1384
+
1385
+ /**
1386
+ * options for the evaluate function
1387
+ */
1388
+ export interface EvaluateOptions {
1389
+
1390
+ /**
1391
+ * argument separator to use when parsing input. set this option to
1392
+ * use a consistent argument separator independent of current locale.
1393
+ */
1394
+ argument_separator?: ',' | ';';
1395
+
1396
+ /**
1397
+ * allow R1C1-style references. the Evaluate function cannot use
1398
+ * relative references (e.g. R[-1]C[0]), so those will always fail.
1399
+ * however it may be useful to use direct R1C1 references (e.g. R3C4),
1400
+ * so we optionally support that behind this flag.
1401
+ */
1402
+ r1c1?: boolean;
1403
+ }
1404
+
1405
+ /**
1406
+ * options for serializing data
1407
+ */
1408
+ export interface SerializeOptions {
1409
+
1410
+ /** optimize for size */
1411
+ optimize?: 'size' | 'speed';
1412
+
1413
+ /** include the rendered/calculated value in export */
1414
+ rendered_values?: boolean;
1415
+
1416
+ /** translate colors to xlsx-friendly values */
1417
+ export_colors?: boolean;
1418
+
1419
+ /** export cells that have no value, but have a border or background color */
1420
+ decorated_cells?: boolean;
1421
+
1422
+ /** prune unused rows/columns */
1423
+ shrink?: boolean;
1424
+
1425
+ /**
1426
+ * include tables. tables will be serialized in the model, so we can
1427
+ * drop them from cells. but you can leave them in if that's useful.
1428
+ */
1429
+ tables?: boolean;
1430
+
1431
+ /** share resources (images, for now) to prevent writing data URIs more than once */
1432
+ share_resources?: boolean;
1433
+
1434
+ /**
1435
+ * if a function has an export() handler, call that
1436
+ */
1437
+ export_functions?: boolean;
1438
+ }
1439
+ export type AnnotationType = 'treb-chart' | 'image' | 'textbox' | 'external';
1440
+ export interface Point {
1441
+ x: number;
1442
+ y: number;
1443
+ }
1444
+
1445
+ /** structure represents rectangle coordinates */
1446
+ export interface IRectangle {
1447
+ top: number;
1448
+ left: number;
1449
+ width: number;
1450
+ height: number;
1451
+ }
1323
1452
  export type CellValue = undefined | string | number | boolean | Complex | DimensionedQuantity;
1324
1453
 
1325
1454
  /**
@@ -1396,26 +1525,6 @@ export interface TableSortOptions {
1396
1525
  }
1397
1526
  export type TableSortType = 'text' | 'numeric' | 'auto';
1398
1527
 
1399
- /**
1400
- * options for the evaluate function
1401
- */
1402
- export interface EvaluateOptions {
1403
-
1404
- /**
1405
- * argument separator to use when parsing input. set this option to
1406
- * use a consistent argument separator independent of current locale.
1407
- */
1408
- argument_separator?: ',' | ';';
1409
-
1410
- /**
1411
- * allow R1C1-style references. the Evaluate function cannot use
1412
- * relative references (e.g. R[-1]C[0]), so those will always fail.
1413
- * however it may be useful to use direct R1C1 references (e.g. R3C4),
1414
- * so we optionally support that behind this flag.
1415
- */
1416
- r1c1?: boolean;
1417
- }
1418
-
1419
1528
  /** clipboard data is a 2d array */
1420
1529
  export type ClipboardData = ClipboardDataElement[][];
1421
1530
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trebco/treb",
3
- "version": "31.3.3",
3
+ "version": "31.4.0",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "homepage": "https://treb.app",
6
6
  "repository": {
@@ -1481,7 +1481,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1481
1481
 
1482
1482
  }
1483
1483
 
1484
- /** @internal */
1484
+ /**
1485
+ * @internalRemarks removing internal flag
1486
+ */
1485
1487
  public ConditionalFormatDuplicateValues(range: RangeReference|undefined, options: ConditionalFormatDuplicateValuesOptions): ConditionalFormat {
1486
1488
 
1487
1489
  return this.AddConditionalFormat({
@@ -1493,7 +1495,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1493
1495
  }
1494
1496
 
1495
1497
  /**
1496
- * @internal
1498
+ * @internalRemarks removing internal flag
1497
1499
  */
1498
1500
  public ConditionalFormatGradient(range: RangeReference|undefined, options: ConditionalFormatGradientOptions|StandardGradient): ConditionalFormat {
1499
1501
 
@@ -1512,7 +1514,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1512
1514
 
1513
1515
  }
1514
1516
 
1515
- /** @internal */
1517
+ /**
1518
+ * @internalRemarks removing internal flag
1519
+ */
1516
1520
  public ConditionalFormatCellMatch(range: RangeReference|undefined, options: ConditionalFormatCellMatchOptions): ConditionalFormat {
1517
1521
 
1518
1522
  const format: ConditionalFormatCellMatch = {
@@ -1528,7 +1532,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1528
1532
  }
1529
1533
 
1530
1534
  /**
1531
- * @internal
1535
+ * @internalRemarks removing internal flag
1532
1536
  */
1533
1537
  public ConditionalFormatExpression(range: RangeReference|undefined, options: CondifionalFormatExpressionOptions): ConditionalFormat {
1534
1538
 
@@ -1561,7 +1565,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1561
1565
  /**
1562
1566
  * remove conditional format
1563
1567
  *
1564
- * @internal
1568
+ * @internalRemarks removing internal flag
1565
1569
  */
1566
1570
  public RemoveConditionalFormat(format: ConditionalFormat) {
1567
1571
  this.grid.RemoveConditionalFormat({ format });
@@ -1572,7 +1576,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1572
1576
  * range). we operate on format objects, meaning we'll remove the whole
1573
1577
  * format object rather than clip the area.
1574
1578
  *
1575
- * @internal
1579
+ * @internalRemarks removing internal flag
1576
1580
  */
1577
1581
  public RemoveConditionalFormats(range?: RangeReference) {
1578
1582
  const area = this.RangeOrSelection(range);
@@ -1602,6 +1606,23 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1602
1606
  // only handle a limited set of commands, then
1603
1607
 
1604
1608
  switch (event.command) {
1609
+ case 'adjust-font-scale':
1610
+ {
1611
+ const delta = Number(event.delta || 0);
1612
+ let scale = this.grid.GetAnnotationStyle()?.font_size;
1613
+
1614
+ if (!scale || scale.unit !== 'em') {
1615
+ scale = { unit: 'em', value: 1 };
1616
+ }
1617
+
1618
+ if (scale) {
1619
+ scale.value += delta;
1620
+ updated_style.font_size = scale;
1621
+ this.grid.ApplyAnnotationStyle(updated_style);
1622
+ }
1623
+ }
1624
+ break;
1625
+
1605
1626
  case 'font-scale':
1606
1627
  {
1607
1628
  const scale = Number(event.scale || 1);
@@ -1629,7 +1650,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1629
1650
  const selection = this.grid.GetSelection();
1630
1651
  if (selection && !selection.empty) {
1631
1652
  const label = selection.area.spreadsheet_label;
1632
- this.InsertAnnotation(`=${func}(${label},,"${label}")`, undefined, undefined, ',');
1653
+
1654
+ if (func === 'Scatter.Plot' || func === 'Scatter.Line') {
1655
+ this.InsertAnnotation(`=${func}(Series(,,${label}),"${label}")`, undefined, undefined, ',');
1656
+ }
1657
+ else {
1658
+ this.InsertAnnotation(`=${func}(${label},,"${label}")`, undefined, undefined, ',');
1659
+ }
1633
1660
  }
1634
1661
  };
1635
1662
 
@@ -1682,6 +1709,41 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1682
1709
  }
1683
1710
  break;
1684
1711
 
1712
+ case 'adjust-font-scale':
1713
+ {
1714
+ let scale = this.selection_state.style?.font_size;
1715
+ const selection = this.grid.GetSelection();
1716
+ const area = this.grid.active_sheet.RealArea(selection.area);
1717
+ const delta = Number(event.delta || 0);
1718
+
1719
+ if (!scale || scale.unit !== 'em') {
1720
+ scale = { unit: 'em', value: 1 };
1721
+ }
1722
+
1723
+ // console.info({scale, delta});
1724
+
1725
+ if (scale && delta && !isNaN(delta)) {
1726
+ scale.value += delta;
1727
+ this.grid.ApplyStyle(undefined, {
1728
+ font_size: scale,
1729
+ }, true);
1730
+ const rows: number[] = [];
1731
+ for (let row = area.start.row; row <= area.end.row; row++) {
1732
+ rows.push(row);
1733
+ }
1734
+
1735
+ // tweak: don't resize row if merged, even if the merged
1736
+ // area is too small
1737
+
1738
+ if (!this.selection_state?.merge) {
1739
+ this.grid.SetRowHeight(rows, undefined, false);
1740
+ }
1741
+
1742
+ }
1743
+
1744
+ }
1745
+ break;
1746
+
1685
1747
  case 'font-scale':
1686
1748
 
1687
1749
  // above we handle 'font-size' events; this comes from a dropdown,
@@ -1695,6 +1757,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1695
1757
  const scale = Number(event.scale || 1);
1696
1758
 
1697
1759
  if (scale && !isNaN(scale)) {
1760
+
1761
+ console.info("FS", scale);
1762
+
1698
1763
  this.grid.ApplyStyle(undefined, {
1699
1764
  //font_size_unit: 'em', font_size_value: scale
1700
1765
  font_size: {
@@ -1709,6 +1774,10 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1709
1774
  // tweak: don't resize row if merged, even if the merged
1710
1775
  // area is too small
1711
1776
 
1777
+ // this should wait, because apply style is async.
1778
+ // actually shouldn't it do that automatically because
1779
+ // this is _also_ async? TODO: check that
1780
+
1712
1781
  if (!this.selection_state?.merge) {
1713
1782
  this.grid.SetRowHeight(rows, undefined, false);
1714
1783
  }
@@ -1773,6 +1842,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1773
1842
  case 'insert-column-chart': insert_annotation('Column.Chart'); break;
1774
1843
  case 'insert-bar-chart': insert_annotation('Bar.Chart'); break;
1775
1844
  case 'insert-line-chart': insert_annotation('Line.Chart'); break;
1845
+ case 'insert-scatter-plot': insert_annotation('Scatter.Plot'); break;
1776
1846
 
1777
1847
  case 'increase-precision':
1778
1848
  case 'decrease-precision':
@@ -23,7 +23,7 @@ export interface BorderToolbarMessage {
23
23
  }
24
24
 
25
25
  export interface AnnotationToolbarMessage {
26
- command: 'insert-image'|'insert-donut-chart'|'insert-line-chart'|'insert-column-chart'|'insert-bar-chart';
26
+ command: 'insert-image'|'insert-donut-chart'|'insert-line-chart'|'insert-column-chart'|'insert-bar-chart'|'insert-scatter-plot';
27
27
  }
28
28
 
29
29
  export interface LayoutToolbarMessage {
@@ -55,6 +55,11 @@ export interface FontScaleToolbarMessage {
55
55
  scale?: number;
56
56
  }
57
57
 
58
+ export interface AdjustFontScaleToolbarMessage {
59
+ command: 'adjust-font-scale';
60
+ delta: number;
61
+ }
62
+
58
63
  export interface FontStackToolbarMessage {
59
64
  command: 'font-stack';
60
65
  font_stack?: string;
@@ -108,5 +113,6 @@ export type ToolbarMessage
108
113
  | IndentMessage
109
114
  | NumberFormatToolbarMessage
110
115
  | FontScaleToolbarMessage
116
+ | AdjustFontScaleToolbarMessage
111
117
  | FontStackToolbarMessage
112
118
  ;
@@ -1474,6 +1474,18 @@ export class Grid extends GridBase {
1474
1474
 
1475
1475
  }
1476
1476
 
1477
+ /** set scale directly */
1478
+ public SetScale(scale: number) {
1479
+ scale = Math.round(scale * 1000) / 1000;
1480
+ scale = Math.min(2, Math.max(scale, .5));
1481
+
1482
+ if (this.options.persist_scale_key) {
1483
+ localStorage.setItem(this.options.persist_scale_key, JSON.stringify({scale}));
1484
+ }
1485
+
1486
+ this.scale = scale;
1487
+ }
1488
+
1477
1489
  /**
1478
1490
  * @param container html container element
1479
1491
  */
@@ -1698,6 +1710,19 @@ export class Grid extends GridBase {
1698
1710
 
1699
1711
  }
1700
1712
 
1713
+ /**
1714
+ *
1715
+ */
1716
+ public GetAnnotationStyle(): CellStyle|undefined {
1717
+ if (this.selected_annotation) {
1718
+ if (this.selected_annotation.data?.style) {
1719
+ return JSON.parse(JSON.stringify(this.selected_annotation.data.style));
1720
+ }
1721
+ return {};
1722
+ }
1723
+ return undefined;
1724
+ }
1725
+
1701
1726
  /**
1702
1727
  *
1703
1728
  */
@@ -2612,7 +2637,7 @@ export class Grid extends GridBase {
2612
2637
 
2613
2638
  const current_width = sheet.GetColumnWidth(column);
2614
2639
  let max_width = 0;
2615
- const padding = 12; // 4 * 2; // FIXME: parameterize
2640
+ const padding = 14; // 4 * 2; // FIXME: parameterize
2616
2641
 
2617
2642
  for (let row = 0; row < sheet.cells.rows; row++) {
2618
2643
  const cell = sheet.CellData({ row, column });
@@ -5386,6 +5411,8 @@ export class Grid extends GridBase {
5386
5411
  */
5387
5412
  private SetInferredType(selection: GridSelection, value: string|undefined, array = false, exec = true, apply_style?: CellStyle) {
5388
5413
 
5414
+ // console.info("SIT", {apply_style});
5415
+
5389
5416
  // validation: cannot change part of an array without changing the
5390
5417
  // whole array. so check the array. separately, if you are entering
5391
5418
  // an array, make sure that no affected cell is part of an existing
@@ -5464,10 +5491,22 @@ export class Grid extends GridBase {
5464
5491
 
5465
5492
  const commands: Command[] = [];
5466
5493
 
5494
+ /*
5495
+
5496
+ this was here to use the currently selected font stack, but it's broken - it
5497
+ clears backgrounds. temp removed in advance of proper fix.
5498
+
5499
+ ...because it was missing the `delta` parameter. I guess that defaults to false?
5500
+
5501
+ we never specified, and it's a boolean in an interface, so it defaults to false
5502
+
5503
+ */
5504
+
5467
5505
  if (apply_style) {
5468
5506
  commands.push({
5469
5507
  key: CommandKey.UpdateStyle,
5470
5508
  style: apply_style,
5509
+ delta: true,
5471
5510
  area: array ? selection.area : selection.target,
5472
5511
  })
5473
5512
  }